Skip to main content
ponderloop

HTML Entity Encoder & Decoder

To put text safely into HTML, replace & < > " and ' with character references: & becomes &amp;, < becomes &lt;, 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 &lt;a href=&quot;/menu?x=1&amp;y=2&quot;&gt;Chef&#x27;s Café: “Crème” — 5 € 😀&lt;/a&gt;. All non-ASCII (numeric) also writes every other non-ASCII character as a hex reference: “Café — 5 € 😀” becomes Caf&#xE9; &#x2014; 5 &#x20AC; &#x1F600;. Named entities uses a name where the HTML standard has one and a number where it has none: the same text becomes Caf&eacute; &mdash; 5 &euro; &#x1F600;. Decoding understands all 2,231 names of the standard, including the 106 legacy ones that work without a semicolon, plus decimal and hex numbers: “&lt;p&gt;Caf&eacute; &amp; cr&#232;me &#x1F600; &copy 2026 &#128;&lt;/p&gt;” 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

Stays in your browser

Your text is processed on this device and never uploaded. It is not saved either: reload the page and it is gone.

Action
Encode mode

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.

The five characters Minimal mode escapes

These are the characters the OWASP guidance says to escape in element content and in quoted attribute values. Computed with the same code as the tool.
CharacterNameNamedDecimalHexWhy
&Ampersand&amp;&#38;&#x26;Starts every character reference, so a literal one must be escaped first.
<Less-than sign&lt;&#60;&#x3C;Starts a tag in element content.
>Greater-than sign&gt;&#62;&#x3E;Ends a tag; escaped for symmetry and for older parsers.
"Double quote&quot;&#34;&#x22;Ends a double-quoted attribute value.
'Apostrophe&#x27;&#39;&#x27;Ends a single-quoted attribute value.

How edge cases decode

Results come from the same decoder as the tool, once as text between tags and once inside a quoted attribute value.
InputIn element textIn an attributeWhy
&amp;& (U+0026)& (U+0026)The normal form, with its semicolon.
&amp& (U+0026)& (U+0026)A legacy name decodes without the semicolon.
&ampx&x&ampxA legacy name followed by a letter: still decoded in text, left alone in an attribute.
&copy=1©=1&copy=1The same exception for “=”, which protects query strings like ?a=1&copy=2.
&notit;¬it;&notit;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.
&#128;€ (U+20AC)€ (U+20AC)Codes 0x80 to 0x9F are read as Windows-1252, so this is the euro sign, not a control code.
&#0;U+FFFDU+FFFDThe null character is not allowed and becomes the replacement character.
&#x110000;U+FFFDU+FFFDAbove the last Unicode code point.
&#xD800;U+FFFDU+FFFDHalf of a surrogate pair is not a character.
&foo;&foo;&foo;Not a known name: kept as typed.

Common named entities

A few of the 2,231 names in the table. “Yes” in the last column means the name also works without its semicolon (106 names do).
EntityCharacterCode pointWorks without “;”
&nbsp;(no-break space)U+00A0Yes
&copy;©U+00A9Yes
&reg;®U+00AEYes
&trade;™U+2122No
&euro;€U+20ACNo
&pound;£U+00A3Yes
&yen;¥U+00A5Yes
&cent;¢U+00A2Yes
&sect;§U+00A7Yes
&para;U+00B6Yes
&deg;°U+00B0Yes
&plusmn;±U+00B1Yes
&frac12;½U+00BDYes
&times;×U+00D7Yes
&divide;÷U+00F7Yes
&middot;·U+00B7Yes
&bull;•U+2022No
&hellip;…U+2026No
&ndash;–U+2013No
&mdash;—U+2014No
&lsquo;‘U+2018No
&rsquo;’U+2019No
&ldquo;“U+201CNo
&rdquo;”U+201DNo
&laquo;«U+00ABYes
&raquo;»U+00BBYes
&larr;←U+2190No
&rarr;→U+2192No
&hearts;♥U+2665No
&check;✓U+2713No
&infin;∞U+221ENo
&ne;≠U+2260No
&le;≤U+2264No
&ge;≥U+2265No

How to encode or decode HTML entities

  1. Choose Encode or Decode. Pick the direction, then paste or type your text. The result updates as you type.
  2. 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 &eacute; where they exist. To decode, choose Element text or Attribute value, which differ for names without a semicolon.
  3. 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”.
  4. 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 &amp;, &#38; and &#x26;?
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 &#x27; and not &apos;?
&apos; exists in XML and in HTML5, but not in HTML 4, and some old parsers and email clients ignore it. The numeric form &#x27; 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 “&amp” or “&copy 2026” decode without a semicolon?
For historical reasons the HTML standard keeps 106 names that browsers accept without the closing semicolon, such as &amp, &lt, &copy and &eacute. 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&copy=2" keeps its query string. The same text between tags would turn &copy into ©. A name with its semicolon decodes everywhere.
What happens to &#0;, &#x110000; and &#xD800;?
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 &#128; is €, as in every browser. Control characters and noncharacters are decoded but flagged.
Why is my text still full of &amp;lt; after decoding?
It was escaped twice: the first round turned < into &lt; and the second turned that & into &amp;, giving &amp;lt;. One round of decoding gives &lt; back. When the tool sees &amp; 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 &eacute;; 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 &amp; &lt; &gt; &quot; and &#x27;. 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 (&plusmn;, not &pm;), otherwise the shortest. Unpaired surrogates, which cannot be encoded, become &#xFFFD;. 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

All toolsHome & DIY calculators