The problem: the browser can't tell your data from your markup
You have a string — a < b && c > d — and you want to display it on a web page. You paste it into your HTML, reload, and the browser eats the < and the > because it thinks they're tags. Or worse: a user submits <script>alert(1)</script> as their username, you render it without encoding, and now you have a cross-site scripting vulnerability. The fix is HTML entity encoding — replacing the characters that have structural meaning in HTML with sequences the browser renders as text, not markup. The hard part isn't the replacement; it's knowing which characters to encode, in what order, and in which of three formats.
Fastest path
Open the HTML Entity Encoder, paste the text, pick a mode, read the output.
Input: a < b && c > d
Mode: Encode → Named → Special chars only
Output: a < b && c > d
The tool encoded the three structural characters (<, >, &) and left the rest alone. The browser now renders the original string verbatim, and there's no angle bracket for it to mistake for a tag. The rest of this guide is why only those characters are mandatory, why the ampersand is encoded first, and what the three formats and four selective modes actually do.
The substance: five mandatory characters, three formats, one ordering rule
The five that must be encoded
HTML reserves five characters for its own syntax. If they appear in your text content, they must be encoded or the browser will misread them.
| Character | Named | Numeric (decimal) | Hex | Why it's reserved |
|---|---|---|---|---|
& |
& |
& |
& |
Starts every entity — ambiguous if unescaped |
< |
< |
< |
< |
Starts a tag |
> |
> |
> |
> |
Ends a tag |
" |
" |
" |
" |
Delimits attribute values |
' |
' |
' |
' |
Delimits attribute values (named entity ' is unreliable in older browsers) |
The first three are mandatory in text content. The last two are mandatory inside attribute values. If you're only displaying text, encode &, <, > and you're safe. If you're stuffing a string into an attribute (value="..."), encode the quote character that matches the delimiter too. The tool's "Special chars only" mode handles all five.
Three formats, one character
< and < and < all render as <. They're the same character in three encodings:
- Named (
<) — human-readable, limited to the ~2,000 entities in the HTML spec. The tool ships ~58 of the most common ones (punctuation, currency, math, arrows, Latin letters). Easy to read in source, impossible to generate for a character that has no named entity. - Numeric / decimal (
<) — the Unicode code point in decimal. Works for every character, not just the ones with names.’is the right single quote;😀is 😀. - Hex (
<) — the same code point in hexadecimal. Preferred by developers who think in hex (0x3Cis<the same way0x41isA). Identical behavior to decimal; the browser decodes both.
The tool's format toggle switches between the three. For the five mandatory characters, named is the convention. For arbitrary Unicode (emoji, CJK, accented Latin), numeric or hex is the only option — there's no named entity for 😀.
The ampersand goes first, always
The ordering rule is the one that bites. You must encode & before you encode anything else. The reason: every entity starts with &. If you encode < first — turning it into < — and then encode &, you get &lt;. The browser decodes that as the literal text <, not as <. You've double-encoded.
The tool encodes ampersands first in a single pass, so a < b && c > d becomes a < b && c > d — correct. A naive encoder that processes characters left-to-right without this ordering produces a &lt; b &amp;&amp; c &gt; d, which renders as the wrong text on the page. This is also why you can't just chain .replace('<', '<').replace('&', '&') — the order is backwards, and the second replace eats the ampersands the first one produced.
The four selective modes
Not every character needs encoding every time. The tool ships four selective modes:
- All — encodes every non-alphanumeric character. Maximum safety, minimum readability. Use this for user-generated content rendered into an attribute, or when you're not sure what's in the string.
- Special — encodes only the five reserved characters (
& < > " '). The right default for text content. Preserves readability;<becomes<butéstaysé. - Non-ASCII — encodes the five special characters plus anything above U+007F. Use this when your target charset is ASCII-only (a legacy system, an email subject line) and
émust becomeé. - Custom — encodes the five special characters plus a user-defined list. Use this when you need to encode a specific set (say, quotes for a JSON-in-HTML context) without touching the rest.
Auto-detection and the decode path
The tool auto-detects whether your input is already encoded and switches to decode mode. The detection is a regex: if the input matches &(#x?[0-9a-fA-F]+|[a-zA-Z]+); — the pattern of a valid entity — it assumes you want to decode, not encode. Paste <hello> and you get <hello> back; paste <hello> and you get <hello>.
The decode path runs in three stages, in order: named entities (via a reverse lookup table), then numeric decimal (&#NNN;), then hex (&#xHH;). The order matters because named entities are a subset — & is also a valid match for the numeric pattern if you squint, so named must run first to consume the whole entity before the numeric regex sees a fragment. Decoding is lossless: < → <, < → <, < → <, all three produce the same character.
Gotchas
- Encode the ampersand first. Always. If your encoder processes characters left-to-right without this rule, it double-encodes. The tool handles this internally; a hand-rolled
.replace()chain usually doesn't. 'is unreliable. The named entity for the apostrophe wasn't in HTML4, and older IE ignores it. Use'(numeric) for the single quote in attribute values. The tool uses'for the apostrophe in named mode for this reason.- Named entities don't cover everything. There's no named entity for 😀 or most CJK characters. If you need to encode arbitrary Unicode, switch to numeric or hex. The tool falls back to numeric when a character has no named entity.
- "Special chars only" is the right default for text content. "All" mode produces output like
elloforello— technically correct, unreadable, and overkill. Use "All" only for untrusted input in sensitive contexts. - Encoding is not the same as escaping for JavaScript. HTML entity encoding prevents the browser from interpreting characters as HTML. It does not prevent a string from breaking out of a JavaScript string literal.
</script>inside a<script>block can still close the tag early. For JS contexts, use a proper JS string escaper (String Escape), not HTML entities. - URLs need a different encoding.
&in a URL query string (?a=1&b=2) is a separator, not an entity. In HTML attribute context it still needs encoding (&), but the URL itself needs percent-encoding (URL Encoder). The two encodings are not interchangeable. - Decoding is not sanitization. Decoding
<script>back to<script>gives you executable markup. If you're decoding user input before rendering, you've undone the protection. Decode for editing; encode for display. - Bulk mode encodes line-by-line. Each line is processed independently, so a multi-line string with entities that span lines won't decode correctly in bulk. Use the single-input mode for cross-line content.
Summary
- Five characters must be encoded:
&<>"'. The first three in text content, all five in attribute values.&is encoded first — always — because every entity starts with an ampersand and encoding it last double-encodes everything. - Three formats, same character: named (
<), numeric decimal (<), hex (<). Named is readable but limited to ~2,000 spec entities; numeric and hex work for any Unicode code point. The tool falls back to numeric when a character has no named entity. - Four selective modes: All (every non-alphanumeric — overkill), Special (the five reserved — the right default for text), Non-ASCII (for ASCII-only targets like email), Custom (user-defined set). Pick Special for content, All for untrusted input in attributes.
- Auto-detection: the tool reads your input and decides encode vs decode from whether it matches the entity pattern. Decode runs named → numeric → hex, in that order, because named is a subset of the numeric pattern.
- Encoding is not escaping. HTML entity encoding prevents HTML injection; it doesn't prevent JS string breakout or URL injection. For JS use String Escape; for URLs use URL Encoder. Decode for editing, encode for display — never the reverse on untrusted input.
- Encode at the HTML Entity Encoder; pair with HTML Minifier to compress the result, URL Encoder for query strings, and String Escape for JavaScript string contexts.