HTML encoder
Escape special characters for HTML documents or decode HTML entities back to plain text.
Docify's HTML encoder escapes the five markup-significant characters in your browser: & → &, < → <, > → >, " → ", and apostrophe → '. The decoder reverses these plus numeric character references like < (decimal) or < (hex). This is not URL encoding, not a sanitizer, and not the full HTML named-entity table. Nothing is uploaded.
How it works
- Encoding replaces markup characters with their entity equivalents. Ampersand is replaced first to prevent double-encoding (e.g.,
<would become<if ampersand came second). - Decoding matches the five named entities plus numeric character references using a regular expression. The hex prefix must be lowercase
x(notX), and all forms require a trailing semicolon. - Numeric references use
String.fromCodePoint()and accept Unicode scalars from 1 to 0x10FFFF. Surrogate code points (0xD800–0xDFFF) and out-of-range values stay as written. - This is not a sanitizer. It does not prevent XSS or validate HTML structure. Use proper sanitization libraries for user-generated content.
Character reference table
| Character | Named entity | Decimal | Hex |
|---|---|---|---|
| & | & | & | & |
| < | < | < | < |
| > | > | > | > |
| " | " | " | " |
| ' | ' or ' | ' | ' |
Named vs Numeric HTML Entities
This page encodes the five markup-significant characters with a mix of named and numeric character references, then decodes those five lowercase names plus decimal and hex numeric refs. A named reference is a mnemonic (<). A numeric one is the Unicode code point: decimal < or hex <. Ampersand is replaced first so a later pass cannot double-escape an entity. This is not URL percent-encoding and not a sanitizer. For the longer comparison, see Named vs Numeric HTML Entities: Names vs Code Points.
| Aspect | Named | Numeric |
|---|---|---|
| Spec | HTML named character references; this page recognizes only amp, lt, gt, quot, and apos | Decimal &#N; or hex &#xN; (WHATWG / HTML numeric character references) |
| Encode | Writes &, <, >, and " | Apostrophe is ' (HTML 4.01 never defined ') |
| Sample sentence | Price: 5 < 10 & 10 > 5, "sale" isn't on. encodes as Price: 5 < 10 & 10 > 5, "sale" isn't on. | |
| Decode | Expands those five lowercase names; , ©, é, &, and ≪ stay written | < and < become <; hex digits may be mixed case, but the x prefix must be lowercase — < stays written |
| Semicolon | < without a trailing semicolon stays < | < without a semicolon stays < |
| Unicode / range | Encode leaves non-ASCII such as é (U+00E9) unchanged; there is no full HTML5 named-entity table | Scalars 1–0x10FFFF except surrogates; é is NFC é; é is NFD e + U+0301; � and � stay written |
Decode of < (lowercase hex digits) is the same < as <. This page is not encodeURIComponent and not a WHATWG HTML parser — browsers may expand more names and accept a missing semicolon. Percent-encoding belongs on URL encoder; composing NFD e + U+0301 to NFC é belongs on Unicode normalizer.
HTML entities in Python and Node
The snippets below escape the five markup-significant characters for HTML text — the same encode path this page uses. They are not URL percent-encoding, not a sanitizer, and not the full HTML named-entity table. For names versus code points, see Named vs Numeric HTML Entities: Names vs Code Points.
Node.js with the same replacements
Node has no built-in HTML encoder. The replacements below match this page: ampersand first, then angle brackets, then quotes, with apostrophe as ' (not '). Decode named entities before & so a once-encoded &lt; stays <:
function encodeHtml(text) {
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
const encoded = encodeHtml('Price: 5 < 10 & 10 > 5, "sale" isn\'t on.');
// Price: 5 < 10 & 10 > 5, "sale" isn't on.
const decoded = encoded
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'|'/g, "'")
.replace(/&/g, '&');
// Price: 5 < 10 & 10 > 5, "sale" isn't on.Python with html.escape
CPython html.escape with quote=True writes the same four named entities as this page, but apostrophe becomes ' instead of '. This page decodes both numeric forms. quote=False leaves quotes and apostrophes unchanged. html.unescape expands the full HTML5 named-entity table ( , ©); this page only expands amp, lt, gt, quot, apos, plus decimal and hex numeric references:
import html
encoded = html.escape('Price: 5 < 10 & 10 > 5, "sale" isn\'t on.', quote=True)
# Price: 5 < 10 & 10 > 5, "sale" isn't on.
decoded = html.unescape(encoded)
# Price: 5 < 10 & 10 > 5, "sale" isn't on.Non-ASCII letters such as é stay unchanged in Node, CPython escape, and this page. Numeric references like < and < still need this page's decimal/hex path, or Python unescape — the five-name replace above does not expand them. Use a sanitizer, not these snippets, for untrusted HTML.
HTML entities in the shell
There is no POSIX HTML encoder. jq 1.7 @html writes the same four named entities this page uses for ampersand, angle brackets, and quotes (&, <, >, "). Apostrophe becomes ' in jq; this page writes '; CPython html.escape writes '. Decode on this page accepts all three. jq is not POSIX.
jq @html
Pass -R so the input is a string — without it, jq 1.7 errors jq: parse error: Invalid numeric literal at line 1, column 6 on this sentence. -r writes the encoded string without extra quotes (without -r the same command writes a JSON string). -s slurps a trailing newline as a literal newline — @html does not turn that newline into an entity. Use printf '%s' or jq -n --arg, not echo with -s:
jq -nr --arg s "Price: 5 < 10 & 10 > 5, \"sale\" isn't on." '$s|@html' # Price: 5 < 10 & 10 > 5, "sale" isn't on. printf '%s' 'hello < world' | jq -Rr @html # hello < world printf '%s' 'hello < world' | jq @html # jq: parse error: Invalid numeric literal at line 1, column 6 printf '%s' 'hello < world' | jq -R @html # "hello < world" printf '%s' 'café' | jq -Rr @html # café printf '%s' "'" | jq -Rr @html # '
Already-encoded text
Ampersand is replaced first, so already-encoded < becomes &lt; — the same double-encoding this page's Encode writes. jq 1.7 has no @htmld. Decode with this page's Decode mode, the Node replacements above, or Python html.unescape (that last one also expands and the rest of the HTML5 named table; this page does not):
printf '%s' '< & >' | jq -Rr @html
# &lt; &amp; &gt;
printf '%s' '<' | jq -Rr @htmld
# jq: error (at <stdin>:0): htmld is not a valid format
jq -nr '{"a":1} | @html'
# {"a":1}@uri percent-encodes UTF-8 bytes; that belongs on the URL encoder, not here. @text leaves < and & unchanged. Tab and newline stay as control characters in jq and on this page — they are not numeric references. Use a sanitizer, not these snippets, for untrusted HTML.
FAQ
- Does this tool upload my text?
- No. Encode, decode, and copy run entirely in your browser using JavaScript string replacement. The page never sends your text to a server.
- Which characters does Encode escape?
- Only the five markup-significant characters: & becomes &, < becomes <, > becomes >, " becomes ", and the apostrophe becomes '. Ampersand is replaced first to prevent double-encoding. Non-ASCII characters like é stay unchanged.
- Why is the apostrophe ' instead of '?
- ' was not defined in HTML 4.01 (only in XML and HTML5). The numeric reference ' is universally supported across all HTML and XML parsers. Decode accepts both forms.
- What named entities does Decode support?
- Decode expands only the five core entities: &, <, >, ", and '. It also decodes decimal (<) and hex (<) numeric character references. Other named entities like or © stay as written.
- Does the trailing semicolon matter?
- Yes. This tool requires a trailing semicolon for all entities. < without a semicolon stays as <, and < without a semicolon stays as <. A WHATWG HTML parser is more lenient, but this tool follows strict parsing rules.
- Is this the same as URL encoding?
- No. HTML encoding escapes markup characters for safe display in HTML documents. URL encoding (percent-encoding) escapes characters for URLs using %XX notation. Use our URL Encoder tool for URL encoding.