HTML entity encode/decode · Guide
HTML Ampersand Entity: When to Write & and When Not To
The ampersand character is written as `&` in HTML source when it is data rather than the beginning of a character reference. Browsers often recover from a bare `&`, which makes mistakes appear harmless until a following word resembles an entity, markup passes through another encoder, or a URL is copied between HTML and HTTP contexts. The reliable rule is to escape for the output context exactly once.
What & means in HTML
& is the named HTML character reference for a literal ampersand. The browser's HTML parser converts it to one & text character in the document. Users see Research & Development; View Source shows Research & Development.
<p>Research & Development</p>
<!-- DOM textContent: Research & Development -->
<!-- Visible text: Research & Development -->The reference is not URL encoding and does not send the five characters & to JavaScript when parsed as markup. %26 is percent-encoding for a URL component; & protects an ampersand from the HTML parser. They solve different parsing layers.
In ordinary HTML text, escaping a bare ampersand is the robust form. It also keeps validators, XML-based tooling and transformations from interpreting the characters after it as a reference name.
Why a bare ampersand can fail silently
An ampersand begins named references such as © and numeric references such as ©. A literal & followed by text can therefore be consumed as a character reference. HTML parsing has compatibility rules and may leave some unknown forms alone, but relying on recovery makes the result dependent on the following characters and context.
<p>Parameters: lang=en&copy=true</p>
<!-- Correct visible text: Parameters: lang=en©=true -->
<p>Symbol: ©</p>
<!-- Visible text: Symbol: © -->The semicolon should be included. HTML accepts a limited set of legacy named references without one, but omission creates ambiguity when letters or digits follow. Emit complete references such as &, < and ".
Do not replace ampersands in an already parsed DOM text node. Assigning textContent = 'A & B' is safe because the browser treats the value as text. Escaping it first displays the literal characters &.
Ampersands inside HTML attributes and URLs
A query string uses & to separate parameters. Inside an HTML attribute, that separator must be represented as & in source so the HTML parser produces the intended URL. The network request still contains &, not &.
<a href="/search?q=tea&page=2">Next page</a>
<!-- Parsed href: /search?q=tea&page=2 -->
<!-- Request target: /search?q=tea&page=2 -->If an ampersand belongs inside a parameter value rather than separating parameters, first URL-encode it as %26, then HTML-escape any structural separators in the complete attribute. For a value rock&roll, the source can be /search?q=rock%26roll&page=2.
This ordering matters: encode each URL key and value, assemble the URL with &, then escape the assembled URL for HTML. HTML entity encoding alone cannot protect data from the query-string parser.
Avoid double escaping
Double escaping turns & into &amp;. After one HTML parse, the user sees the text & instead of &. It usually happens when application code escapes a value and a template engine correctly escapes it again.
// Let textContent perform contextual handling.
const label = 'Terms & Conditions';
document.querySelector('#label').textContent = label;
// Wrong for textContent: this displays Terms & Conditions
// element.textContent = 'Terms & Conditions';Keep values raw inside the application and escape at the final output boundary. In auto-escaping templates, print the raw string through the normal escaped interpolation. Use a raw-HTML directive only for trusted markup, never merely to fix visible & text.
A database containing a mixture of raw and pre-escaped values cannot be corrected by encoding everything again. Identify the storage contract, migrate pre-escaped records back to raw text carefully, and make every writer follow the same rule.
Encode safely on the server
Use a standard context-aware encoder rather than a chain of manual replacements. Replacement order is fragile: escaping < and then escaping & can re-escape references the first step created. Library functions also handle quotes and the chosen character set.
$raw = 'Tea & <strong>coffee</strong>';
$safe = htmlspecialchars($raw, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
echo $safe;
// Tea & <strong>coffee</strong>htmlspecialchars is suitable for normal HTML text and quoted attributes when configured for UTF-8. ENT_SUBSTITUTE replaces invalid byte sequences rather than returning an empty result. Do not decode user input and then inject it as HTML; decoding removes a representation layer, not malicious meaning.
HTML encoding differs from JavaScript, CSS and URL encoding. A value embedded in a script block needs a JavaScript-safe serialiser such as JSON encoding, ideally delivered as data rather than executable source.
Literal ampersands in code and data formats
The entity syntax applies while parsing HTML markup. It does not apply to a JavaScript string in an external .js file, JSON response, CSS file or HTTP request target. Writing & there usually creates six literal characters because no HTML parser decodes them.
// External JavaScript and JSON values use a literal ampersand.
const company = 'A & B';
const payload = JSON.stringify({ company });
// {"company":"A & B"}
// HTML source uses the entity:
// <span>A & B</span>Inline JavaScript inside an HTML attribute crosses multiple grammars and is easy to encode incorrectly. Prefer event listeners and data-* attributes so the browser parses data as HTML once and code separately.
XML requires an ampersand to be escaped more strictly; a bare one makes the document not well-formed. XHTML served as XML therefore does not get HTML's forgiving error recovery.
Diagnose ampersand bugs by checking each layer
Inspect View Source, the DOM property and the actual network request separately. Source may correctly contain &, the DOM will expose &, and DevTools' network panel will show the request separator. Comparing only rendered text cannot reveal which parser changed the value.
const link = document.querySelector('a');
console.log(link.getAttribute('href')); // parsed attribute text
console.log(link.href); // resolved absolute URL
console.log(link.textContent); // rendered text, no markupIf users see &, look for double encoding or an escaped value assigned to textContent. If a query parameter disappears, decide whether its ampersand was meant as structure (&) or value data (%26). If markup validation fails, find bare ampersands in text and attributes.
The general model is simple: raw application data, URL-component encoding when building a URL, then HTML escaping when inserting that URL into markup. Reverse those layers only when parsing the corresponding format, never with a global search-and-replace.
Frequently asked questions
What is the HTML entity for an ampersand?
It is &. In HTML source that reference becomes one literal & character in the parsed DOM and on screen.
Do I always need to escape an ampersand in HTML?
Escape it as & when it is literal data in HTML text or an attribute. Browsers tolerate some bare ampersands, but the result can change when following text resembles a character reference, and XML parsers reject them.
Should URLs in HTML use & or &?
In HTML source, write query separators as & inside the attribute. After HTML parsing the link and the HTTP request contain an ordinary &; & is not sent as part of the parameter name.
What is the difference between & and %26?
& escapes a literal ampersand for the HTML parser. %26 encodes an ampersand that belongs inside a URL component, preventing the query parser from treating it as a separator.
Why does my page display & literally?
The value was probably escaped twice, or pre-escaped text was assigned through textContent. Store raw text and let the final HTML output boundary escape it exactly once.
Can I decode HTML entities to make user HTML safe?
No. Decoding changes representation and may turn harmless-looking text back into active markup. To display user input, keep it as text and encode it; to allow markup, use a maintained HTML sanitiser with an explicit policy.
Ready to try it?
Open the free browser-based HTML entity encode/decode and apply what you just read — no sign-up, runs locally.
Open the HTML entity encode/decode tool