What an HTML entity is

An entity is a stand-in that lets a character appear in a document without being read as markup. &lt; renders as < instead of opening a tag, &amp; renders as & instead of starting another entity. The three notations are interchangeable: named (&auml;), decimal (&#228;) and hexadecimal (&#xE4;).

Two separate motivations hide behind the same mechanism, and conflating them causes most of the confusion around this topic. Escaping & < > " ' is about safety: without it, user input can close a tag and open a script. Encoding ä or as an entity is about portability: a way to keep a document readable in ASCII-only channels. The first is mandatory, the second is a choice, and this encoder keeps them apart with the --minimal flag.

How to use this encoder

Paste on the left, read the escaped HTML on the right. By default the five critical characters are escaped and every non-ASCII character becomes an entity, with readable names where HTML defines one.

  1. Paste your text. Snippets of code, user-generated content, an entire template fragment.
  2. Pick the depth. --minimal for a UTF-8 page where only safety matters; leave it off when the output has to survive an ASCII-only channel.
  3. Check the entities count under the panes, then copy or download.

--named

On by default: uses &auml;, &euro;, &mdash; where HTML defines a name, and numeric references for everything else. Named entities are easier to read in source; numeric ones are universally understood, including by XML parsers, which know only five names. Turn --named off if the output will be consumed as XML.

--minimal

Escapes only & < > " ' and leaves every other character as-is. This is what a modern UTF-8 page wants: safe, and the text stays readable and searchable in the source. It is also what htmlspecialchars() and html.escape() do.

The five characters that matter

CharacterEntityRequired inWhat happens without it
&&amp;text and attributesFollowing text may be swallowed as an entity
<&lt;textOpens a tag; the injection vector
>&gt;textCloses a tag early in some parser states
"&quot;attributesEnds a double-quoted attribute, allowing new ones
'&#39;attributesEnds a single-quoted attribute

Order matters when you implement this yourself: escape the ampersand first, then everything else. Doing it the other way turns < into &lt; and then into &amp;lt;, which renders as the visible text &lt;. That double-escaping bug shows up on live sites constantly, usually because two layers both escape, and it is the reason our entity decoder can decode repeatedly.

Escaping depends on context

HTML escaping is correct for exactly two places: element text and quoted attribute values. Elsewhere it is either insufficient or actively wrong.

  • Inside <script>: the parser does not process entities in a script block, so &quot; arrives as those literal characters and breaks your JavaScript. Serialise data with JSON.stringify instead, or put it in a <script type="application/json"> block.
  • In an href or src: escaping does not stop javascript: URLs. Validate the scheme, then percent-encode the value with the URL encoder.
  • In an unquoted attribute: a space or a slash ends the attribute even when quotes are escaped. Always quote your attributes.
  • Inside a style attribute or CSS: CSS has its own escaping rules and its own injection surface.

The practical takeaway is not to escape more aggressively but to escape in the right place: at output time, in the encoding the destination expects. Templates that auto-escape (Astro, Svelte, Jinja, Twig, React JSX) get this right by default, and manual escaping on top of them produces the double-escaped output described above.

Named, decimal or hex

CharacterNamedDecimalHex
&&amp;&#38;&#x26;
ä&auml;&#228;&#xE4;
&euro;&#8364;&#x20AC;
&mdash;&#8212;&#x2014;
non-breaking space&nbsp;&#160;&#xA0;
😀none&#128512;&#x1F600;

HTML5 defines around 2,200 named entities, XML defines five. So named entities are convenient in HTML and a parse error in XML, RSS and XHTML served as XML, where &auml; without a DTD is undefined. When the output is XML-ish, turn off --named. For emoji and other astral-plane characters there is no name anyway; this encoder emits one numeric reference for the full code point rather than two surrogate halves, which is what a naive per-UTF-16-unit implementation gets wrong.

Between the two numeric forms this encoder always writes decimal. Parsers treat them as identical, and hex only reads better if you are comparing against a Unicode chart, which is not what anyone is doing at the point of escaping a string. A toggle for it would be one more control for a difference nobody consuming the HTML can see.

Do you still need entities in a UTF-8 world

For a normal web page: only for the five security-relevant characters. Everything else can be a literal character, and there are good reasons to keep it that way, since the source stays readable, the file stays smaller, and search inside the codebase actually finds the word.

Where entities still earn their place: email templates that pass through gateways with unpredictable charset handling; CSV and legacy CMS imports where a UTF-8 declaration is not guaranteed; and characters that look identical to something else in an editor. A non-breaking space and a normal space are indistinguishable on screen, so writing &nbsp; is documentation rather than paranoia. The same goes for a soft hyphen or a zero-width joiner sitting in a product name.

Escaping questions

How do I show HTML code on a web page without it rendering?

Escape the angle brackets and the ampersand, then wrap the result in pre and code. Once <div> is written as &lt;div&gt;, the browser prints the characters instead of building an element, and pre keeps your line breaks and indentation. The ampersand has to be escaped as well, otherwise a snippet containing &copy; renders as ©. Syntax highlighters expect the same thing: escaped text in the source, highlighted markup added on top. Anything that ends up inside innerHTML unescaped is not just a display problem, it is the standard route for stored XSS.

What is an HTML entity?

An HTML entity is a way to write a character using only ASCII: &amp; for &, &lt; for <, &auml; for ä. It exists so that characters with structural meaning in HTML can appear as text, and so documents in ASCII-only encodings can still contain any Unicode character. Entities come in three forms: named (&copy;), decimal numeric (&#169;) and hexadecimal numeric (&#xA9;), all producing the same character.

Which characters must be escaped in HTML?

Five, and the list is short enough to memorise: & becomes &amp;, < becomes &lt;, > becomes &gt;, " becomes &quot; and ' becomes &#39;. The ampersand has to be first, otherwise you double-escape your own output. In element text, & and < are strictly required; inside an attribute value, the quote character that delimits the attribute is required as well. Escaping all five everywhere is simpler and never wrong.

Does escaping HTML prevent XSS?

It prevents the most common form of it, injection into HTML text or attribute values, but only when the escaping matches the context. Text inside a <script> block, a style attribute, or a URL in href needs different treatment: JavaScript string escaping, CSS escaping, or URL validation. The rule that holds up is to escape at the point of output, in the encoding that the destination context requires, and to use a template engine that does it automatically.

What is the difference between &quot; and &#39;?

Only their origin. &quot; is a named entity for the double quote and has existed since HTML 2.0; the single quote (apostrophe) has the named entity &apos;, but that name was only added in HTML5 and older Internet Explorer versions do not understand it. The numeric reference &#39; works everywhere, which is why most escaping libraries emit it instead. This tool does the same.

Do I still need entities for umlauts and accents?

Not for correctness, as long as your page declares UTF-8 via <meta charset="utf-8"> and the file is actually saved as UTF-8. Then ä, é and € can appear as plain characters. Entities remain useful in three situations: content that travels through systems with unclear encoding (email templates, legacy CMS fields), files that must stay pure ASCII, and characters that are invisible or ambiguous in an editor, like a non-breaking space, where &nbsp; documents the intent.

Why does my page show ä instead of ä?

The page is UTF-8 but the browser reads it as Latin-1, or a Latin-1 file is being served as UTF-8. This is a charset declaration problem, not an entity problem, and escaping the characters is a workaround rather than a fix. Check that the file is saved as UTF-8, that <meta charset="utf-8"> is present in the first kilobyte of the document, and that the Content-Type header agrees with it. The header wins over the meta tag when they disagree.

How do I escape HTML in JavaScript, Python or PHP?

JavaScript has no built-in escape function; the common approach is a replace chain over the five characters, or letting the DOM do it via element.textContent = value, which never interprets markup. Python: html.escape(s, quote=True). PHP: htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8"), where the ENT_QUOTES flag matters because the default leaves single quotes untouched. In templates, prefer the engine's auto-escaping over manual calls.

Why does my page show &amp; or &lt; as visible text?

Something escaped an already escaped string. Each pass turns the & of an existing entity into &amp;, so &lt; becomes &amp;lt; and the reader sees the entity spelled out instead of the character. It happens when a template engine auto-escapes a value that the application layer escaped first, or when data is escaped on the way into the database and again on the way out. Fix it by escaping exactly once, at the point of output, and store raw text everywhere else. Stripping the extra layer with a decoder repairs the display but leaves the double-escaping in place for the next record.

Should I escape HTML when saving data or when displaying it?

When displaying it. Store the raw text the user typed and escape at the point of output, because that is the only place where you know the destination, HTML text, an attribute, a JSON response, a CSV export or a plain-text email. Escaping on input corrupts the data for every consumer that is not a web page, breaks search and sorting, and produces the double-escaped output above as soon as the template escapes it again. Validate on input, escape on output is the rule that holds. Rejecting or sanitising markup on input is a separate decision and only makes sense when the field is genuinely allowed to contain HTML.

What is a non-breaking space and when should I use it?

A non-breaking space (&nbsp;, U+00A0) renders as a space but prevents a line break at that position, and consecutive ones are not collapsed the way normal spaces are. Legitimate uses: keeping a number with its unit ("5 kg"), a name with its title, or a value with its currency symbol. Using it for layout spacing is a habit from the table-layout era; CSS margins and padding do that job without polluting the text content, which also matters for anyone copying the text out.