HTML Entity Encoder and Decoder_
Both directions, one page. Encode turns characters into entities so a browser prints them instead of parsing them; decode turns entities back into the characters they stand for. The default escapes the five that actually change how a document is read and leaves everything else alone, because escaping accented letters makes output larger and no safer.
The ampersand is escaped before anything else, which sounds like an implementation detail and is the entire difference between working code and a page displaying < to its readers. Encode a string twice here and you will see exactly that happen, on purpose.
- Input
- Text to encode, or entity-laden text to decode. Named, decimal and hexadecimal references are all understood on the way back.
- Output
- Entities in the form you chose — minimal, named where a name exists, or every non-ASCII character — or the decoded text, with any reference that is not a real entity left exactly where it was.
- Processing
- String work in this tab. No DOM is used to decode, so the result cannot depend on what a browser would have tolerated.
- Limits
- The named table covers the entities people use, not all 2,231 in HTML5 — the rest are emitted numerically, which every parser accepts. Decoding an unknown name leaves it untouched rather than deleting it.
- Encoding is not sanitising
- Escaping the five characters makes text safe to place in an HTML text node. It does not make a URL safe in an href, a value safe inside a script tag, or a string safe in a CSS expression — those are different contexts with different rules, and javascript: in a link survives entity encoding intact. Encode for display; use a real sanitiser for markup you did not write.
Five characters, and why the order matters
What an entity is for
HTML has no way to tell a < that begins a tag from one that is part of your sentence, so the language provides a second spelling: write < and the parser produces the character without treating it as syntax. Everything else entities are used for — accented letters, arrows, currency symbols — is a convenience left over from the days before UTF-8 was universal. Only &, <, >, " and ' change how a document parses, and those five are the ones that matter.
The ampersand goes first, always
Every entity begins with an ampersand, so an escaper that handles < before & will escape its own output. The < becomes <, then the ampersand pass finds that new ampersand and produces &lt;, and the page renders the literal text < where a less-than sign was meant to be. This is the most common bug in hand-written escaping and the fix is a single line of ordering.
Double-encoding, and why your page shows its own escapes
The same failure happens across a system rather than inside a function: a framework escapes on the way into the database, and the template escapes again on the way out. Nothing is broken, no error is raised, and users see Q&A in a heading. The rule that prevents it is to store raw text and escape once, at the moment of output — and if you are looking at doubled escapes now, decoding twice on this page will confirm that is what happened.
Named, decimal or hexadecimal
©, © and © all produce ©. Names are readable and incomplete — a check mark has none, which is why searching for one finds nothing useful. Numeric references work for every character that exists and are the safe default when generating output automatically. One name is worth knowing about: ' is HTML5 and was never in HTML4, so ' is what this page emits for an apostrophe.
Escaping the whole alphabet does not help
Some tools escape every non-ASCII character by default, turning café into café. On a UTF-8 page — which is every page now — this adds bytes, hurts readability and improves nothing, because an accented letter was never going to be parsed as markup. It is genuinely useful in exactly one situation: when the output has to survive a pipeline that mangles anything above ASCII, such as an old mail system or a database column with the wrong collation.
Pick a direction, paste, read
- 01Encode is selected by default. Press Decode to go the other way — it is the same tool and the same page.
- 02Leave the escape setting on the five that matter unless you have a reason. Named and everything-non-ASCII exist for specific pipelines, not for safety.
- 03Watch for the warning above the panes: it appears when your input already contains entities, which is when encoding again would double them.
- 04Press Swap to move the result into the input, which is how you check a round trip or peel a second layer off doubly-encoded text.
Showing code samples on a page
A snippet containing tags has to appear as text. Without escaping the browser runs it as markup and the sample vanishes into the layout.
<div class="box">Hello</div>
<div class="box">Hello</div>
A heading that renders as Q&amp;A
The value was escaped when it was saved and escaped again when it was rendered. Decoding once removes the extra layer and shows what is really stored.
Q&amp;A with the team
Q&A with the team Decode twice → Q&A with the team
Reading an entity-laden export
A CMS or an RSS feed hands you text full of references. Decoding gives back the characters so the content can be searched, counted or migrated.
Café — 50% off ✓
Café — 50% off ✓
Putting a value inside an attribute
A quotation mark in an attribute value ends the attribute early, and everything after it becomes markup. This is where escaping stops being cosmetic.
26" monitor
<img alt="26" monitor">
The entities worth knowing
| Character | Named | Decimal | Hex | Note |
|---|---|---|---|---|
| & | & | & | & | Escape this one FIRST or every other escape gets double-encoded. |
| < | < | < | < | Opens a tag. Unescaped user input containing this is how markup injection starts. |
| > | > | > | > | Not strictly required in text, escaped anyway because a stray one confuses readers and some parsers. |
| " | " | " | " | Required inside a double-quoted attribute value. |
| ' | ' | ' | ' | ' is HTML5 only — ' works everywhere, which is why it is the safer output. |
| (non-breaking space) | A space that does not collapse and does not break a line. Not an ordinary space, which is why it is invisible in a diff. | |||
| © | © | © | © | Copyright sign. |
| ® | ® | ® | ® | Registered trademark. |
| ™ | ™ | ™ | ™ | Trademark. |
| – | – | – | – | En dash — ranges of numbers. |
| — | — | — | — | Em dash — the punctuation one. |
| • | • | • | • | Bullet. |
| … | … | … | … | Ellipsis, as one character rather than three dots. |
| → | → | → | → | Right arrow. |
| € | € | € | € | Euro sign. |
| ✓ | — | ✓ | ✓ | Check mark. It has NO named entity, which is why searching for one turns up nothing. |
Every row is checked in the test suite by decoding all three spellings and comparing them to the character in the first column. The non-breaking space row was wrong on the first draft — an ordinary space had been typed where the character should have been, invisible to every reader and caught by that comparison.
Habits that prevent doubled escapes
- Store raw text and escape once, at output. Escaping on the way into storage guarantees a second escape somewhere downstream.
- Escape the ampersand before anything else, or use a library that does. Every entity starts with one, so getting the order wrong escapes your own output.
- Use
'rather than'for apostrophes. The named form is HTML5 only and older parsers print it literally. - Do not escape non-ASCII characters without a reason. On a UTF-8 page it adds bytes and readability cost for no safety benefit.
- Remember that entity encoding is not URL encoding. A space is
%20in a URL and stays a space in HTML — the two schemes look similar and share nothing.
What escaping does not protect you from
A javascript: URL in an href
Entity encoding leaves the scheme intact, and HTML decodes attribute values before following them. Escaping a link target does not make it safe — checking the scheme does.
Anything inside a script or style block
Those elements have their own parsing rules and HTML entities are not decoded inside them. Text escaped for HTML and dropped into a script tag is still executable.
Unquoted attribute values
If the attribute has no quotes, a space is enough to end it and start a new one. Escaping quotation marks accomplishes nothing when there were none to begin with.
Double-encoding on the way in
Escaping before storage means the escape is part of the data. Every later render escapes again, and no single change fixes it — the stored values have to be decoded once.
Coverage, forms and behaviour
- Encoded always
- Ampersand, less-than, greater-than, double quote and apostrophe — the five that change how a document parses. The ampersand is handled first by construction rather than by ordering a chain of replacements.
- Named coverage
- Around 160 entities: the Latin-1 block, punctuation, arrows, currency and the common symbols. HTML5 defines 2,231, most of them mathematical; anything outside the table is emitted numerically, which every parser accepts.
- Decoding
- Named, decimal and hexadecimal references, case-insensitively for the x. Surrogate halves and code points above the Unicode range are rejected rather than turned into replacement characters.
- Unknown references
- Left exactly as they were and reported. A string containing &foo; is far more likely to be a query parameter than a broken entity.
- Not used
- No DOM. Decoding through a browser element would inherit whatever that browser tolerates, and the answer would differ between them.
- Network
- None from tool code. A test sweep calls every function this page uses with
fetchandXMLHttpRequestreplaced by stubs that throw, so a stray request fails the build instead of shipping. Disconnect from the network and the page still works.
Questions about HTML entities, encoding and decoding
Which characters do I actually need to escape in HTML?
Five: & < > " and '. Those are the ones that change how the document parses. Everything else — accented letters, symbols, arrows — is optional on a UTF-8 page and escaping it adds size without adding safety.
Why does my page show &amp; instead of &?
The text was escaped twice. Something escaped it on the way into storage and the template escaped it again on the way out, so the ampersand of the first escape became the entity of the second. Decode the stored values once and escape only at output.
What is the difference between &#39; and &apos;?
They produce the same apostrophe, but ' was introduced in HTML5 and does not exist in HTML4, so an older parser prints it as literal text. ' is understood everywhere, which is why it is what this page emits.
Is HTML encoding the same as URL encoding?
No, and mixing them is a common source of broken links. URL encoding uses percent signs and applies to addresses — a space becomes %20. HTML entities use ampersands and apply to document text. A URL inside an HTML attribute may need both, applied in that order.
Does HTML encoding prevent XSS?
It prevents one class of it — untrusted text placed into an HTML text node. It does not help inside a script tag, inside a style block, in an unquoted attribute, or in a javascript: URL, because those contexts have different parsing rules. Escaping is for display; use a real sanitiser for markup you did not write.
What is the HTML entity for a check mark?
There is no named one. Use ✓ or ✓ — this is why searching for a name returns nothing useful. Names cover a few hundred characters; numeric references cover every character there is.
Should I escape non-ASCII characters like é or 日?
Not normally. On a UTF-8 page they are ordinary characters and can never be parsed as markup. Escaping them is worth doing only when the output has to survive a pipeline that mangles anything above ASCII, such as a legacy mail system.
What happens to an entity you do not recognise?
It is left exactly where it was and listed. Deleting an unrecognised &foo; would look tidy and quietly corrupt data — in practice such a string is usually a query parameter rather than a broken entity.
Does my text leave the browser?
No. The work is JavaScript running in this tab. Every function it calls is covered by a test that stubs fetch and XMLHttpRequest to throw, so a request that slipped in would break the build rather than reach a server — and you can confirm it for yourself by disconnecting and carrying on.