|$ curl https://forge-ai.dev/api/markdown?path=docs/html/entities
$cat docs/html-entities.md
updated Today·30 min read·published

HTML Entities

HTMLEntitiesSecurityBeginner🎯Free Tools
Introduction

HTML character references (entities) let you include characters that would otherwise be parsed as markup, or that are awkward to type. In UTF-8 documents you can usually paste real characters directly — entities remain essential for &, <, attribute-safe quotes, invisible characters, and documentation that shows markup as text.

This guide covers named, decimal, and hex references; escaping rules; XSS-related escaping; the difference between &nbsp; and CSS spacing; emoji; RTL marks; practical tables; and the common confusion between HTML entities and encodeURIComponent.

Named vs numeric vs hex

Three equivalent forms exist for many characters. Named references are readable; numeric forms always work for any Unicode code point.

FormExampleNotes
Named&lt; &nbsp; &copy;Finite set defined by HTML
Decimal numeric&#60; &#160;&# followed by decimal + ;
Hex numeric&#x3C; &#xA0;&#x followed by hex + ;
forms.html
HTML
1<!-- All represent < -->
2&lt; &#60; &#x3C; &#x3c;
3
4<!-- Non-breaking space -->
5&nbsp; &#160; &#xA0;
6
7<!-- Prefer real UTF-8 when possible -->
8<p>Copyright © 2026</p>
9<p>Copyright &copy; 2026</p>

best practice

In modern UTF-8 pages, type readable characters for typography (—, “ ”, …). Always escape &, < (and quotes in attributes) when they are data, not markup.
📝

note

Trailing semicolon is required for ambiguous named references and always recommended. Omitting it can cause greedy parsing bugs.
When to escape

Context determines what must be escaped. Text content, attributes, and script/style elements have different rules.

ContextMust escape / avoidDetails
Text content& and < (and often >)Prevents tag open / entity open
Attribute values& and the quoting charUse &quot; or &apos; as needed
URL in hrefURL encoding, not HTML entitiesPercent-encode first, then attribute-escape
Inside <script>Do not HTML-entity escape JSUse proper JS escaping / JSON
textarea content< and &Shown as text to users
escape.html
HTML
1<!-- Text -->
2<p>Use &lt;button&gt; for actions &amp; links for navigation.</p>
3
4<!-- Attribute with double quotes -->
5<div data-label="Tom &amp; Jerry" title="5 &lt; 6"></div>
6
7<!-- Safer: avoid embedding raw HTML in attributes entirely -->

warning

Escaping with entities inside <script> does not work like text content — the script data state is different. Never “HTML-escape” JSON into a script tag and assume it is safe.
XSS-related escaping

Cross-site scripting often starts as unescaped user input inserted into HTML. Entity escaping is one layer — not a complete security program. Prefer textContent, contextual encoders, and sanitizers over hand-rolled replace chains.

xss.js
JavaScript
1// Safe for text content
2el.textContent = userInput; // no HTML parsing
3
4// Dangerous
5el.innerHTML = userInput;
6
7// Minimal escape for text nodes (illustrative — use vetted libraries)
8function escapeHtml(s) {
9 return s
10 .replace(/&/g, '&amp;')
11 .replace(/</g, '&lt;')
12 .replace(/>/g, '&gt;')
13 .replace(/"/g, '&quot;')
14 .replace(/'/g, '&#39;');
15}
16
17// Attribute context needs the same family of escapes
18img.setAttribute('alt', userInput); // prefer setAttribute/text APIs
xss-example.html
HTML
1<!-- Attacker input: <img src=x onerror=alert(1)> -->
2<!-- If injected via innerHTML, executes -->
3<!-- If inserted as textContent, shows as text -->

danger

Replacing only < is not enough — & and quotes matter. Attribute injection and javascript: URLs bypass naive filters. Use DOM APIs or audited sanitizers (e.g. DOMPurify) for rich HTML.

best practice

Defense in depth: HTTP-only cookies, CSP, escaping, sanitization, and avoiding dangerous sinks (innerHTML, document.write, eval).
  vs CSS gap

&nbsp; (U+00A0) is a non-breaking space character. It prevents line breaks at that position and preserves a space that will not collapse. It is not a layout system. Prefer margin, gap, padding, or white-space for UI spacing.

ApproachUse when
&nbsp;Keep “10 MB” or “Mr. Smith” on one line
CSS margin/gapSpace between components
paddingInner spacing inside a box
width/flexAlignment and columns
white-space: prePreserve multiple spaces intentionally
nbsp.html
HTML
1<!-- OK: unit stays with number -->
2<p>File size: 10&nbsp;MB</p>
3
4<!-- Bad layout hack -->
5<p>Title&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Price</p>
6
7<!-- Good -->
8<div class="row" style="display:flex;gap:1rem;justify-content:space-between">
9 <span>Title</span><span>Price</span>
10</div>
preview

info

&nbsp; still counts as a character for copy/paste and string length. Excessive nbsp from Word/HTML email is a common CMS mess — normalize to regular spaces where breaks are fine.
Emoji and symbols

Emoji are Unicode characters. You can paste them directly in UTF-8 HTML or use numeric references. Named entities do not exist for most emoji. Be aware of ZWJ sequences, skin tones, and variation selectors.

emoji.html
HTML
1<p>Ship it 🚀</p>
2<p>Ship it &#x1F680;</p>
3<p>Family: 👪 or ZWJ sequences</p>
4<p>⚠︎ vs ⚠️ (text vs emoji presentation)</p>
📝

note

Do not use emoji as the sole accessible name for controls — provide text or aria-label. Emoji rendering differs by OS and font.
RTL and bidirectional marks

Bidirectional text uses invisible format characters. Prefer markup (dir, bdi, bdo) over sprinkling entities, but knowing the marks helps when debugging.

NameReferenceRole
LRM&lrm; / U+200ELeft-to-right mark
RLM&rlm; / U+200FRight-to-left mark
LRE/RLE/PDFlegacy embeddingsPrefer dir/bdo
ALMU+061CArabic letter mark
bidi.html
HTML
1<p dir="rtl">مرحبا World</p>
2<p>User <bdi>مرحبا</bdi> submitted a ticket.</p>
3<p>File named <bdo dir="ltr">01-report.pdf</bdo></p>

best practice

Use <bdi> for user-generated fragments of unknown direction. Use dir="auto" carefully — it estimates from the first strong character.
Useful entity tables

Everyday references you will actually type.

CharNamedDecimalHex
&&amp;&#38;&#x26;
<&lt;&#60;&#x3C;
>&gt;&#62;&#x3E;
"&quot;&#34;&#x22;
'&apos;&#39;&#x27;
nbsp&nbsp;&#160;&#xA0;
&mdash;&#8212;&#x2014;
&ndash;&#8211;&#x2013;
&hellip;&#8230;&#x2026;
©&copy;&#169;&#xA9;
®&reg;&#174;&#xAE;
&euro;&#8364;&#x20AC;
×&times;&#215;&#xD7;
÷&divide;&#247;&#xF7;
CharNamedUse
‹ ›&lsaquo; &rsaquo;Single angle quotes
« »&laquo; &raquo;Guillemets
·&middot;Separators
&bull;Bullets in prose
°&deg;Degrees
±&plusmn;Plus-minus
² ³&sup2; &sup3;Prefer <sup> for a11y math
½&frac12;Or write 1/2

info

Bookmark the WHATWG named character references list when you need obscure names — but prefer UTF-8 glyphs in content.
encodeURIComponent vs HTML entities

encodeURIComponent percent-encodes bytes for URL components. HTML entities encode characters for HTML parsing. They solve different problems and are not interchangeable.

encode.js
JavaScript
1const name = 'Tom & Jerry';
2
3// Wrong for URLs
4const bad = '/search?q=' + name.replace('&', '&amp;');
5
6// Right for query params
7const good = '/search?q=' + encodeURIComponent(name);
8// → /search?q=Tom%20%26%20Jerry
9
10// Right for HTML text
11const html = `<p>${escapeHtml(name)}</p>`;
12// → <p>Tom &amp; Jerry</p>
13
14// Composing both: build URL, then put URL into an attribute
15const href = '/search?q=' + encodeURIComponent(name);
16el.innerHTML = `<a href="${escapeHtml(href)}">Search</a>`;
APIOutput alphabetContext
encodeURIComponent%xxQuery, path segments
encodeURI%xx (keeps :/?#)Full URLs carefully
HTML entities&…;HTML text/attrs
JSON.stringifyJS string escapesScript data / JSON
CSS escapes\\Inside style contexts

danger

Double-encoding bugs are common: HTML-escaping a URL so & becomes & in a way that breaks the server, or percent-encoding already-escaped HTML. Encode for the sink you are writing to, once, in the right order.
Live demo
preview
Best practices
untitled.text
TEXT
1[ ] UTF-8 document + charset meta
2[ ] Escape & and < in text from untrusted/data sources
3[ ] Escape quotes in attributes (or use setAttribute)
4[ ] Never treat entities as URL encoding
5[ ] Prefer CSS for layout spacing over &nbsp; spam
6[ ] Prefer dir/bdi over invisible bidi entities
7[ ] Use textContent / sanitizer instead of DIY filters for XSS
8[ ] Show markup examples with &lt;…&gt; so they do not become real tags
Ambiguous ampersands

An ampersand followed by characters that look like a character reference can confuse authors and validators. Historically, ambiguous ampersands were discouraged. In practice, write &amp; whenever you mean a literal ampersand — especially in URLs inside HTML source.

ampersands.html
HTML
1<!-- Fragile -->
2<a href="/search?a=1&b=2">Search</a>
3
4<!-- Clear and valid style -->
5<a href="/search?a=1&amp;b=2">Search</a>
6
7<!-- Built in JS: encode then attribute-escape if needed -->
8<a id="q">Search</a>
9<script>
10 const url = '/search?' + new URLSearchParams({ a: '1', b: '2' });
11 document.getElementById('q').href = url; // DOM API — no HTML entity needed
12</script>

info

Prefer DOM property assignment for URLs generated in JavaScript. You avoid HTML entity issues entirely because you are not serializing through the HTML parser.
Decoding and round-trips

Browsers decode character references when parsing HTML into the DOM. The DOM stores characters, not the entity syntax. Serializing with innerHTML may re-escape as needed. Do not try to “preserve” entity spelling through the DOM — it is not guaranteed.

decode.js
JavaScript
1const div = document.createElement('div');
2div.innerHTML = '&amp;lt;hi&amp;gt;';
3console.log(div.textContent); // "<hi>"
4console.log(div.innerHTML); // "&lt;hi&gt;" (typical re-escape)
$Blueprint — Engineering Documentation·Section ID: HTML-ENTITIES·Revision: 2.0

Community

Get help on Slack, Discord or VIP

Stuck on a guide? Join the community and ask.