HTML Entity Encoder & Decoder
To put text safely into HTML, replace & < > " and ' with character references: & becomes &, < becomes <, and so on. That is Minimal mode, and the example “<a href="/menu?x=1&y=2">Chef's Café: “Crème” — 5 € 😀</a>” becomes <a href="/menu?x=1&y=2">Chef's Café: “Crème” — 5 € 😀</a>. All non-ASCII (numeric) also writes every other non-ASCII character as a hex reference: “Café — 5 € 😀” becomes Café — 5 € 😀. Named entities uses a name where the HTML standard has one and a number where it has none: the same text becomes Café — 5 € 😀. Decoding understands all 2,231 names of the standard, including the 106 legacy ones that work without a semicolon, plus decimal and hex numbers: “<p>Café & crème 😀 © 2026 €</p>” decodes to <p>Café & crème 😀 © 2026 €</p>. Invalid numbers become U+FFFD, as the HTML specification says. Nothing leaves your browser.
Updated Runs in your browser: nothing you enter is uploadedHow this tool works
Your text is processed on this device and never uploaded. It is not saved either: reload the page and it is gone.
Escapes only & < > " and '. That is enough to put text safely in element content or a quoted attribute; other characters stay as they are.
Result
Escaped 8 characters: 56 characters became 87 characters.
This text looks escaped twice (it contains & followed by a reference), so the result still has references in it.
The five characters Minimal mode escapes
| Character | Name | Named | Decimal | Hex | Why |
|---|---|---|---|---|---|
| & | Ampersand | & | & | & | Starts every character reference, so a literal one must be escaped first. |
| < | Less-than sign | < | < | < | Starts a tag in element content. |
| > | Greater-than sign | > | > | > | Ends a tag; escaped for symmetry and for older parsers. |
| " | Double quote | " | " | " | Ends a double-quoted attribute value. |
| ' | Apostrophe | ' | ' | ' | Ends a single-quoted attribute value. |
How edge cases decode
| Input | In element text | In an attribute | Why |
|---|---|---|---|
| & | & (U+0026) | & (U+0026) | The normal form, with its semicolon. |
| & | & (U+0026) | & (U+0026) | A legacy name decodes without the semicolon. |
| &x | &x | &x | A legacy name followed by a letter: still decoded in text, left alone in an attribute. |
| ©=1 | ©=1 | ©=1 | The same exception for “=”, which protects query strings like ?a=1©=2. |
| ¬it; | ¬it; | ¬it; | No such name, so the longest legacy prefix “not” wins and “it;” stays. |
| &euro | &euro | &euro | “euro” is not a legacy name, so it needs its semicolon. |
| € | € (U+20AC) | € (U+20AC) | Codes 0x80 to 0x9F are read as Windows-1252, so this is the euro sign, not a control code. |
| � | U+FFFD | U+FFFD | The null character is not allowed and becomes the replacement character. |
| � | U+FFFD | U+FFFD | Above the last Unicode code point. |
| � | U+FFFD | U+FFFD | Half of a surrogate pair is not a character. |
| &foo; | &foo; | &foo; | Not a known name: kept as typed. |
Common named entities
| Entity | Character | Code point | Works without “;” |
|---|---|---|---|
| | (no-break space) | U+00A0 | Yes |
| © | © | U+00A9 | Yes |
| ® | ® | U+00AE | Yes |
| ™ | ™ | U+2122 | No |
| € | € | U+20AC | No |
| £ | £ | U+00A3 | Yes |
| ¥ | ¥ | U+00A5 | Yes |
| ¢ | ¢ | U+00A2 | Yes |
| § | § | U+00A7 | Yes |
| ¶ | ¶ | U+00B6 | Yes |
| ° | ° | U+00B0 | Yes |
| ± | ± | U+00B1 | Yes |
| ½ | ½ | U+00BD | Yes |
| × | × | U+00D7 | Yes |
| ÷ | ÷ | U+00F7 | Yes |
| · | · | U+00B7 | Yes |
| • | • | U+2022 | No |
| … | … | U+2026 | No |
| – | – | U+2013 | No |
| — | — | U+2014 | No |
| ‘ | ‘ | U+2018 | No |
| ’ | ’ | U+2019 | No |
| “ | “ | U+201C | No |
| ” | ” | U+201D | No |
| « | « | U+00AB | Yes |
| » | » | U+00BB | Yes |
| ← | ← | U+2190 | No |
| → | → | U+2192 | No |
| ♥ | ♥ | U+2665 | No |
| ✓ | ✓ | U+2713 | No |
| ∞ | ∞ | U+221E | No |
| ≠ | ≠ | U+2260 | No |
| ≤ | ≤ | U+2264 | No |
| ≥ | ≥ | U+2265 | No |
How to encode or decode HTML entities
- Choose Encode or Decode. Pick the direction, then paste or type your text. The result updates as you type.
- Pick the mode. To encode, Minimal escapes the five characters HTML needs, All non-ASCII (numeric) also writes every other character as &#xHEX;, and Named entities uses names such as é where they exist. To decode, choose Element text or Attribute value, which differ for names without a semicolon.
- Check the messages. Decoding lists each problem with its position: a missing semicolon, an unknown name, or a number that became U+FFFD. If the text was escaped twice, press “Decode again”.
- Copy the result. Use Copy to put the result on the clipboard. The result is plain text, so paste it into your code or template.
Frequently asked questions
- Which characters must be escaped in HTML?
- Escape & < > " and ' when you put untrusted text into element content or into a quoted attribute value. That is the rule in the OWASP Cross Site Scripting Prevention Cheat Sheet, and it is what Minimal mode does. Always quote attribute values: an unquoted value can be ended by a space or a slash, which escaping the five characters does not stop.
- Is HTML escaping enough to prevent XSS?
- Only for the places it is meant for: element content and quoted attribute values. It is not enough inside a script block, a style block, an event-handler attribute, a URL such as href="javascript:…" or an unquoted attribute, each of which needs its own encoding or a different approach. The safest habit is to let a templating framework escape by default and to set text with textContent rather than innerHTML.
- What is the difference between &, & and &?
- Nothing once the browser has parsed them: all three stand for the ampersand, U+0026. The first is the name, the second the decimal code point and the third the hexadecimal one. Names are easier to read; numbers work for every character, including the ones that have no name.
- Why does the tool write the apostrophe as ' and not '?
- ' exists in XML and in HTML5, but not in HTML 4, and some old parsers and email clients ignore it. The numeric form ' works everywhere, and it is the form the OWASP guidance gives. A decoder understands both.
- Do I need to encode non-ASCII characters like é or €?
- Not if your page is served as UTF-8 (declare it with <meta charset="utf-8"> or the Content-Type header): the characters can be written as they are. Numeric or named references help when the text travels through something limited to ASCII, such as some email systems, or when you want an invisible character such as a no-break space to be visible in the source.
- Why does “&” or “© 2026” decode without a semicolon?
- For historical reasons the HTML standard keeps 106 names that browsers accept without the closing semicolon, such as &, <, © and é. Longer names like &euro or &hellip need the semicolon. Decoding reports a missing semicolon but still decodes, as a browser does. Always write the semicolon when you encode.
- Why does the result differ between Element text and Attribute value?
- Inside an attribute value, a legacy name without a semicolon that is followed by a letter, digit or “=” is not decoded, so a link like href="?a=1©=2" keeps its query string. The same text between tags would turn © into ©. A name with its semicolon decodes everywhere.
- What happens to �, � and �?
- The HTML standard replaces a null reference, a number above U+10FFFF and a surrogate half (U+D800 to U+DFFF) with U+FFFD, the replacement character, and the decoder lists each one. Numbers from 128 to 159 are read as Windows-1252 characters, so € is €, as in every browser. Control characters and noncharacters are decoded but flagged.
- Why is my text still full of &lt; after decoding?
- It was escaped twice: the first round turned < into < and the second turned that & into &, giving &lt;. One round of decoding gives < back. When the tool sees & followed by a reference it offers “Decode again”.
- Is my text sent anywhere?
- No. Encoding and decoding run in your browser and nothing is uploaded or stored. The list of 2,231 names is a small file the page downloads from this site only when it is needed, for example when you decode text containing a name like é; your text is never part of that request. The result is shown in a text box as plain text, never as HTML.
How it works
Encoding walks the text one Unicode code point at a time. In every mode & < > " and ' become & < > " and '. Numeric mode writes each other non-ASCII code point as &#x followed by its hexadecimal value; named mode looks it up in a table built from the standard’s 2,231 names and falls back to the numeric form. Only names for a single character are used, and where a character has several names the HTML 4 name wins (±, not ±), otherwise the shortest. Unpaired surrogates, which cannot be encoded, become �. Decoding follows the “character reference state” of the HTML Standard: the longest name in the table wins, a name without a semicolon counts only if it is one of the legacy names, and in an attribute value a legacy name followed by “=” or an alphanumeric character is left as typed. Numbers go through the “numeric character reference end state”: null, values above U+10FFFF and surrogates become U+FFFD, 0x80 to 0x9F are remapped through the Windows-1252 table, and control characters and noncharacters are decoded but reported. The named table is the standard’s entities.json. It is checked in the test suite against the HTML parser built into jsdom for every name, and random mixes of references are decoded by both and compared. Results are written to text boxes and text nodes only, never inserted as HTML.
Sources
- WHATWG HTML Standard: Named character references (the table of 2,231 entities)
- WHATWG HTML Standard: Character reference state (tokenizer)
- WHATWG HTML Standard: Numeric character reference end state
- WHATWG HTML Standard: entities.json
- OWASP Cross Site Scripting Prevention Cheat Sheet (HTML escaping rules)
- OWASP Top 10 2021: A03 Injection
More free tools
- URL Encode & DecodePercent-encode or decode URLs and query strings with correct UTF-8, split a URL into parts and parameters, and catch double-encoding. Runs in your browser.
- Base64 Encode & DecodeEncode text or a file to Base64 and decode it back, with correct UTF-8 for emoji and any language, URL-safe and MIME variants. Runs in your browser.
- Text to Binary ConverterConvert text to binary, hex, octal or decimal bytes and back. UTF-8 by default (é is 2 bytes, an emoji 4) or UTF-16, with a per-character breakdown.
- Markdown Table GeneratorBuild a GitHub Markdown table from an editable grid or pasted CSV, TSV or spreadsheet cells. Set column alignment, pad columns, and parse a table back.
- Word CounterCount words, characters, sentences and reading time, and check your text against X, LinkedIn, Instagram, SMS and meta description limits.
- Case ConverterConvert text to UPPERCASE, lowercase, Title Case, Sentence case, camelCase, PascalCase, snake_case, kebab-case or CONSTANT_CASE. Stays in your browser.