HTML escape and unescape
Spell text so it can sit safely inside HTML, or read character references back to text — all 2,231 named ones, not just the five everyone remembers.
- SECURE
- NO UPLOADS
- NO SIGNUP
- BROWSER BASED
- FREE
- FOREVER.
Support us with a link or a share
- Characters in
- —
- References written
- —
- Characters out
- —
Nothing at the counter yet.
A textarea rewrites CRLF to LF. The HTML specification requires it, before any script can look, so pasted text arrives with 0 CRLF pairs and 0 lone LF no matter what you copied. If your line endings are the point, open the file instead.
A UTF-8 page accepts café and 😀 exactly as they are. Turn this on when the HTML goes somewhere that mangles UTF-8, such as an old email template or a Latin-1 database column.
What gets escaped, and why
| Character | Written as | Why |
|---|---|---|
| & | & | An ampersand starts every character reference, so a literal one has to be spelled first. |
| < | < | A less-than sign opens a tag. Unescaped, the text after it can become markup. |
| > | > | Not strictly required in text, but escaped so the output is safe in every context. |
| " | " | Ends an attribute value written in double quotes. |
| ' | ' | Ends an attribute value written in single quotes. ' works everywhere; ' did not exist in HTML 4. |
| CR | | Carriage return. A browser turns a raw CR LF into a plain LF while parsing, so CR only survives as a reference. |
| Tab | unchanged | Legal in HTML exactly as it is, so it stays raw — and looks like a space in the result. |
| NUL | � | Written so it is visible, but HTML cannot carry it: every browser shows U+FFFD (�) instead. |
| anything else | &#xHHHH; | Only when you ask for ASCII-only output. Tabs, line feeds, accents and emoji are legal in HTML exactly as they are. |
Unescaping reads all 2,231 named character references in the WHATWG HTML standard — including the 106 legacy names such as   that browsers still accept without a semicolon — plus decimal and hexadecimal ones. A name outside that table is kept as written and listed, never silently dropped.
Nothing you type or open here is uploaded, put in the URL, or written to a log. The escaping runs in this tab.
What an HTML escape actually does
HTML uses a handful of ordinary keyboard characters as syntax. A less-than sign opens a
tag, an ampersand starts a character reference, and a quotation mark ends an attribute
value. The moment the text you want to display contains one of those characters, the
browser can no longer tell your content from the page's structure. Escaping resolves
the ambiguity by replacing each troublesome character with a character reference that
means the same thing but cannot be mistaken for markup: & for the
ampersand, < and > for the angle brackets,
" for the double quote and ' for the
apostrophe.
How many of those five are strictly necessary depends on where the text lands. Between tags, in what the specification calls text content, only the ampersand and the less-than sign can do harm. Inside an attribute value, the quote that wraps the value matters too, because an unescaped one closes it and lets whatever follows become a new attribute. This page escapes all five in every case. The output is therefore a little longer than the minimum, but it is safe to paste into either context, and you never have to stop and work out which one you are in before trusting the result.
What HTML escaping does not do
Escaping is not a sanitizer, and treating it as one is the most expensive mistake
people make with this kind of tool. It protects exactly two contexts: text between tags
and a quoted attribute value. It offers no protection inside a <script>
block, where the rules are JavaScript's rather than HTML's; none inside an event
handler attribute such as onclick, where the value is decoded and then
executed; none inside a style attribute; and none inside a URL. The string
javascript:alert(1) contains no character this page would touch, so it
passes through unchanged and still runs if it ends up in an href. If you
accept markup from users, you need an allow-list sanitizer and a content security
policy. Escaping is one layer of output encoding for one context, and it should be
described that way.
Unescaping: the full table, not the famous five
Reading references back is where most online decoders quietly fall short. They
recognize &, < and a few friends, then leave
é, ♥ or –
sitting in the result as if nothing were wrong. This page reads all 2,231 named
character references in the WHATWG HTML standard, generated from the standard's own
machine-readable list, along with decimal and hexadecimal references such as
é and é. It also follows the browser's
exceptions rather than the literal number: € becomes a euro sign
because browsers read that range as Windows-1252, and � becomes the
replacement character. Each of those gets a remark with its position.
There are 106 legacy names,   and © among
them, that a browser still accepts without the closing semicolon. They are decoded the
way a browser decodes them in text, and the page says when it did so, because inside an
attribute value a browser would leave ©=2 alone. A name that is not
in the table at all, such as &bogus;, is kept exactly as written and
listed. Nothing is dropped silently, and nothing is guessed.
Line endings, and the one character HTML cannot carry
A <textarea> rewrites every carriage-return-and-line-feed pair to a
single line feed before any script can read the field, so text you paste here has
already lost its Windows line endings. The counter next to the field shows what
actually arrived. If the line endings matter, open the file instead: it is read byte by
byte, and each carriage return is written as . That is not
decoration. A browser parsing HTML also turns a raw CR LF into a plain LF, so a numeric
reference is the only spelling that brings the carriage return back out.
The null character is the exception to every round trip. A raw one is thrown away in
text and replaced in attributes, and � becomes U+FFFD everywhere, so
no spelling survives a browser. The page writes it as � so you can
see where it was, and warns before showing the result. Invisible characters that do
survive, such as zero-width joiners, are easier to diagnose with
the invisible character inspector.
Text that was already escaped
If your input already contains &lt;, escaping it again produces
&amp;lt;. That looks like a bug and is the only correct answer:
the tool cannot know whether the ampersand is syntax or content. This page counts the
references already present, says so before the result, and offers to unescape instead.
Unescaping removes exactly one layer and tells you when another remains. The same
double-encoding trap exists for URLs, where the URL decoder
handles it the same way, and for strings bound for a JSON payload, which
the JSON escape tool spells with backslashes instead of
ampersands. If the text is headed into an XML document instead,
the XML escape tool knows only XML’s five named entities
and flags rather than decoding it.
Where this sits among the HTML tools
This page works on text that is going into HTML, or coming out of it one reference at a time. To lay out a whole document over indented lines, use the HTML formatter. To strip the tags from a page and keep only what a reader sees, the HTML to text converter does that and decodes references on the way. If you are writing content rather than escaping it, the Markdown to HTML converter turns plain prose into markup for you.
Your text stays in this tab
All of the work above is done by code running in this tab. The one file it fetches, the reference table, comes from this site the first time you type, and that request carries none of your text. The address bar never gains a copy of your input, and there is no server log for it to appear in. That matters for a tool people use on template fragments, email bodies and configuration values. If you would rather verify than trust, keep your developer tools' network tab open while you work: after that single table download, typing produces no requests at all.
Questions
What must be escaped for HTML, and what is optional?
In ordinary text only two are strictly required: the ampersand, because it starts every character reference, and the less-than sign, because it starts a tag. Inside an attribute value the quote character that wraps the value has to be escaped as well. This tool escapes all five of the usual suspects — &, <, >, " and ' — in every case, so the result is safe wherever you paste it without first having to decide which context it lands in. Everything else, including accented letters and emoji, is legal in a UTF-8 page exactly as it is.
Does escaping HTML protect my page from XSS?
Only in the two places it was designed for: text between tags, and a quoted attribute value. It does nothing inside a <script> block, an event handler such as onclick, a style attribute, or a URL — javascript:alert(1) contains no character that needs escaping, so it passes through untouched and still runs if it ends up in an href. Escaping is one layer of output encoding for one context. It is not a sanitizer, and if you are accepting HTML from users you need an allow-list sanitizer and a content security policy, not this page.
Where do Windows line endings go when I paste text into the field?
Into a line feed, before this page is involved. Browsers normalize the value of every textarea, so a CR LF pair arrives as LF alone and there is no earlier copy for a script to recover. For that reason the counter beside the field reports what actually arrived rather than what you meant to paste. Choosing a file avoids the problem, since its bytes are read without passing through a form control. The escaped output then spells each carriage return as , and that spelling is deliberate: an HTML parser performs the same normalization on raw markup, so a numeric reference is how a CR reaches the reader intact.
Which named entities does unescape understand?
All of them: the 2,231 named character references in the WHATWG HTML standard, from & and to ≂̸ and 𝔄, including the 106 legacy names such as © and é that browsers still read without a trailing semicolon. Decimal and hexadecimal references are read as well, with the same exceptions a browser makes — € becomes € and � becomes U+FFFD. A name that is not in the table, such as &bogus;, is kept exactly as written and listed with its position rather than silently left behind.
Is my text sent to a server?
No. The escaping and unescaping are performed by code in this tab. The table of named references is a file on this site that loads the first time you type, so no third party sees a request either. Your input is never added to the address bar, and there is no log for it to end up in. To verify it yourself, keep the network tab of your developer tools open while you work: apart from that one table download, which carries none of your text, typing produces no requests at all.