HTML escaping replaces the handful of characters that would otherwise be read as markup with entity references, so that text stays text. It is a small operation with an outsized reputation, because getting it wrong is how cross-site scripting happens — and because "escape the input" is advice that is subtly, dangerously incomplete.
Five characters, and the order you replace them in
The set is small: & becomes &, < becomes <, > becomes >, " becomes " and ' becomes '. Everything else can stay as it is.
There is a classic bug hiding in that list. If you replace the characters one at a time and handle & last, you destroy your own work: < becomes <, then the & you just introduced becomes &, and the output is &lt; — a literal, visible "<" on the page instead of a less-than sign. The ampersand must always be escaped first, because every other replacement introduces one.
This tool sidesteps the trap entirely by matching all five characters in one pass and replacing each exactly once, so the order never arises. That is the more robust shape for this kind of code, and worth copying: a single regex with a lookup table cannot double-encode, whereas a chain of replace calls depends on a developer remembering an invariant.
Why the apostrophe is numeric
Look closely and the single quote becomes ' rather than ', which looks inconsistent next to ". It is deliberate. ' was defined in XML and only reached HTML in version 5 — it is not part of HTML 4, and very old parsers will render it literally as the four characters ' rather than as an apostrophe.
The numeric reference ' has always worked everywhere. This is a small thing, but it is the kind of small thing that shows up as mangled text in an email client rendering HTML from 2003, and the numeric form costs nothing.
Escaping is context-dependent — this is the part that matters
Here is the misconception worth dismantling: there is no such thing as "escaped HTML" in the abstract. There is only text escaped correctly for a specific place, and the same escaping that is perfectly safe in one position is useless in another.
Between tags, escaping these five characters is sufficient. Inside a quoted attribute, it is also sufficient — provided the attribute actually has quotes. Write <img src=VALUE> without them and an escaped value containing a space still breaks out: x onerror=alert(1) contains no character that HTML escaping touches, and it becomes an attribute. The quotes are doing the security work, not the escaping.
It gets worse elsewhere. Inside a <script> block, HTML rules do not apply — you need JavaScript string escaping, and the sequence </script> anywhere inside a string literal ends the block regardless of what surrounds it. Inside a URL attribute, HTML escaping does nothing about javascript: as a scheme. Inside a style attribute, CSS has its own escape syntax. Five different contexts, five different rules, and a template engine that only knows one of them will happily produce a hole.
Decoding is the opposite of safety
Encoding makes text inert. Decoding takes inert text and makes it live again. So decoding something and then putting it into a page with innerHTML undoes the exact protection the encoding provided — and this is a real pattern in real code, usually written by someone who thought "decode" meant "clean up".
This tool is safe to decode with because it does nothing with the result except show it to you in a textarea, which cannot execute anything. What you do afterwards is where the risk lives. If you are decoding entities in order to insert the result into a page, use textContent rather than innerHTML, and if you genuinely need to render user-supplied HTML, you need a sanitiser like DOMPurify — an allowlist of safe tags and attributes — not an entity decoder.
Common questions
Is my text sent to a server?
No. This tool is marked "client": the replacement runs in your browser tab and nothing is transmitted or stored.
Does encoding and then decoding give me back exactly what I started with?
Yes. The five replacements are reversible and unambiguous, so a round trip through this tool returns the original text character for character, ampersands and quotes included. That is not true of every escaping scheme, but it is true of this one.
Is escaping enough to prevent XSS?
Only when it matches the context, as described above. The honest short answer is that manual escaping is the fragile way to do this. Modern frameworks — React, Vue, Angular, and any current server-side template engine — escape by default and know which context they are in. That is the actual defence. A tool like this one is for inspecting and understanding a value, not for being the security layer of an application.
What about and all the other named entities?
The HTML specification defines over two thousand of them, and almost none are needed any more. In a UTF-8 document you can write é, ©, — and 😀 directly, and that is more readable than é, © and — ever were. The exceptions worth keeping are the five that are structural, plus where you specifically want a space that will not break across lines. Named entities elsewhere are a habit inherited from a time when encodings were unreliable.
Why does my encoded text show &lt; instead of <?
Something encoded it twice. The first pass turned < into <, and the second pass saw the & in that result and turned it into &. Look for a template that escapes a value which was already escaped upstream — this is common when one layer helpfully escapes and another does it again "to be safe". Escape once, at the point of output.