HTML Encoding Guide: How Browsers Process Entities
What Is HTML Encoding?
HTML encoding converts characters that have special meaning in HTML into safe entity sequences. When you write < instead of <, you tell the browser to display a less-than sign — not open a tag.
Encoding protects your markup from breaking and your users from injection attacks. Every web developer touches HTML encoding, whether manually or through a framework's auto-escaping.
Why Encode Special Characters?
Prevent markup breakage
Five characters can destroy your HTML if left unencoded:
| Character | Entity | Why it matters |
|---|---|---|
& | & | Starts every entity reference |
< | < | Opens an HTML tag |
> | > | Closes an HTML tag |
" | " | Delimits attribute values |
' | ' | Delimits attribute values (HTML5/XML) |
A single unencoded & in a paragraph can cause the browser to misread everything after it as a broken entity.
Stop XSS attacks
When you render user input as HTML, unencoded <script> tags execute. Entity encoding defangs the payload — <script> becomes <script>, and the browser renders it as harmless text.
Display symbols correctly
Currency signs, mathematical operators, and typographic marks often need entities when your editor or source control cannot handle the raw Unicode character.
How Browsers Process Entities
Understanding the parsing order helps you avoid subtle bugs.
Step 1: Tokenization
The browser's HTML tokenizer reads the raw byte stream character by character. When it encounters &, it enters "entity state" and collects characters until it hits ; or a non-entity character.
Step 2: Entity resolution
The tokenizer looks up the entity name in its internal table. If it finds a match — & → &, © → © — it replaces the entire entity with the corresponding character. If no match exists, the browser treats the & and following text as literal content.
Step 3: DOM construction
The resolved characters feed into the DOM builder. At this point, < and > that arrived via entity resolution are plain text nodes — not markup. This is why <div> renders as the visible text <div> instead of creating a DOM element.
Key insight: Entity resolution happens before the browser builds DOM nodes. An entity can never "escape" into markup once the tokenizer resolves it.
Common Mistakes
Double encoding
Encoding a string that already contains entities produces garbled output:
<!-- Original -->
<p>5 > 3</p>
<!-- Double-encoded (wrong) -->
<p>5 &gt; 3</p>
<!-- Renders as: 5 > 3 (literal text, not "5 > 3") -->
This happens when a framework auto-escapes content that you already encoded manually. Encode once — at the boundary where the data enters HTML context.
Wrong encoding order
When a URL with query parameters sits inside an HTML attribute, you need both URL encoding and HTML encoding — but the order matters.
<!-- WRONG: HTML-encode first, URL-encode second -->
<a href="/search?q=red%26blue">Link</a>
<!-- The %26 is URL-safe but the & before it still needs & -->
<!-- CORRECT: URL-encode data values, then HTML-encode the & separators -->
<a href="/search?q=red%26blue&sort=newest">Link</a>
Rule: URL-encode your data values first. Then HTML-encode the & characters that separate query parameters when the URL lives inside an HTML attribute.
Encoding the wrong context
HTML entity encoding protects HTML text and attributes. It does not protect JavaScript strings:
<!-- WRONG: entity encoding inside a script tag -->
<script>
var name = "Robert's Company"; // Syntax error in JS
</script>
<!-- CORRECT: use JavaScript string escaping -->
<script>
var name = "Robert's Company"; // Or Robert\'s Company
</script>
Each output context — HTML text, HTML attributes, JavaScript, CSS, URLs — requires its own escaping strategy.
Forgetting the semicolon
HTML5 allows some named entities without a semicolon, but this creates ambiguity:
<p>I work at AT&T</p>
<!-- Browser sees &T — not a valid entity, renders as-is, but behavior differs across parsers -->
<p>I work at AT&T</p>
<!-- Always correct and unambiguous -->
Always include the semicolon. It eliminates parser ambiguity and makes your intent explicit.
Encoding in Practice
Server-side rendering
Most template engines auto-encode by default:
- Vue —
{{ }}interpolations auto-escape HTML - React — JSX expressions auto-escape
- Blade (Laravel) —
{{ }}auto-escapes; use{!! !!}for raw output - Jinja2 (Python) —
{{ }}auto-escapes when autoescape is on
Use raw output directives only when you intentionally trust the content.
Client-side JavaScript
// Encoding — safe for HTML text
function encodeHtml(str) {
const el = document.createElement('div')
el.textContent = str
return el.innerHTML
}
// Decoding — convert entities back to characters
function decodeHtml(str) {
const el = document.createElement('div')
el.innerHTML = str
return el.textContent
}
Node.js
Use a dedicated library outside the browser:
import { encode, decode } from 'he'
encode('5 > 3 & 2 < 4') // "5 > 3 & 2 < 4"
decode('© 2026') // "© 2026"
Encoding Checklist
- Encode all user-supplied data before rendering it in HTML
- Use your framework's auto-escaping by default
- Never double-encode — encode once at the HTML boundary
- Match your encoding to the output context (HTML ≠ JavaScript ≠ CSS ≠ URLs)
- Always terminate named entities with a semicolon
- Test rendered output with characters like
<,>,&,",'
Key Takeaways
- HTML encoding replaces markup-significant characters with entity sequences
- Browsers resolve entities during tokenization, before building the DOM
- Double encoding and wrong encoding order are the two most common bugs
- Entity encoding only protects HTML contexts — use context-appropriate escaping elsewhere
- Always include the semicolon on named entities to avoid parser ambiguity
- Frameworks auto-escape by default; prefer that over manual encoding
Related Guides
Try It Yourself
Encode and decode HTML entities instantly with our free HTML Encoder/Decoder tool. Paste any text and get properly encoded output in one click.