Escape text into HTML entities so a stray angle bracket renders as a character instead of a tag. Use it to show code on a page, or to find out why a user's apostrophe broke a template. Choose Named, Numeric or Hex entities depending on what will read the output.
<a href="/search?q=cats&safe=on" title='Ryan’s picks'>Cats & dogs</a> <a href="/search?q=cats&safe=on" title='Ryan’s picks'>Cats & dogs</a> Encode & first, always. Encoding it last turns every entity you already wrote into visible text: < becomes &lt;.
Without these, a user typing <script> gets a script tag instead of the words they meant.
Required only inside an attribute. Escaping them everywhere costs nothing, and a value can then move from text into an attribute without opening a hole.
Optional. Turn on Encode all non-ASCII when the text has to pass through a Latin-1 database or an old email gateway that mangles UTF-8.
The same string needs different treatment depending on where it lands. In HTML text, escaping the five characters above is enough. Inside an unquoted attribute, a space ends the value. Inside a script block, HTML escaping does not help and you need JSON encoding instead. Inside a URL, you want percent-encoding, not entities.
Escape at output, never at input. Pre-escaped text in storage breaks every consumer that is not HTML, and it is how &amp; ends up in a database. Let the template engine do it: Blade, Twig, Django and JSX all escape by default, so review each place where your code deliberately bypasses that.
// Escape for HTML text and attribute values
const escapeHtml = (s) =>
s.replace(/&/g, "&") // & first, always
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
console.log(escapeHtml('<a href="x">Cats & dogs</a>'));
// In practice, do not build HTML by hand at all:
el.textContent = userInput; // safe, no escaping needed
el.setAttribute("title", userInput); // safe
el.innerHTML = "<b>" + userInput + "</b>"; // this is the bug textContent and setAttribute escape for you. Use a manual escape only when you are producing a string that something else will parse as HTML.
<?php
$text = '<a href="x">Cats & dogs</a>';
// ENT_QUOTES escapes both quote styles; the third argument avoids
// silently returning an empty string on invalid UTF-8.
echo htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), PHP_EOL;
// htmlentities() also escapes every accented character.
// Only useful if the output is not UTF-8.
echo htmlentities('Café', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), PHP_EOL;
// In Blade, {{ $value }} already does htmlspecialchars.
// {!! $value !!} does not, which is exactly when to be careful. import html
text = '<a href="x">Cats & dogs</a>'
print(html.escape(text)) # quote=True by default
print(html.escape(text, quote=False)) # leaves " and ' alone
# Django and Jinja2 autoescape in templates. The dangerous move
# is turning it off:
# {{ value|safe }} Django
# {{ value|safe }} Jinja2
# Both mean "I have already made sure this is safe", so be sure. XML predefines exactly five entities: & < > " '. HTML5 defines around 2,200 more, including and é, which is why an XML parser rejects HTML that uses them. If the output has to be valid XML or XHTML, use numeric references instead of named ones.
Escape the ampersand first. If you escape it last, every entity you already produced gets its & turned into &, so < becomes &lt; and renders as visible text.
This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.
By default, the five that matter for correctness: < > & " and '. Turn on Encode all non-ASCII and every accented letter, symbol and emoji is escaped too. Use that when the text has to pass through a Latin-1 pipeline.
Use named entities such as & when people will read the source. Use numeric ones such as & when the output must also parse as XML, since XML knows only five predefined names.
Escaping the right way in the right place does. Escape when you output, not when you store, and use the escaping that matches the context: HTML text, an attribute value and a script block each need different treatment. Use this box for debugging; in production, let your template engine escape.
The text was already escaped once and you escaped it again. Run it through the HTML decoder first, then encode once.
In HTML text, no. Inside a single-quoted attribute, yes, or the value ends early. We recommend escaping it everywhere, so a value can move into an attribute without breaking.
Nothing, to the browser. & and & both mean the ampersand, and every HTML and XML parser accepts both. Hex is the Unicode code point written the way the charts show it, so é is easy to check against U+00E9 and matches the \u00e9 form used in CSS and JavaScript. Decimal is what older tools and many CMS editors emit. Pick whichever your codebase already uses.
Tick Encode all non-ASCII. Every character above the ASCII range then becomes one entity per code point: with Hex selected, é becomes é and an emoji such as the grinning face becomes 😀, and with Numeric they are é and 😀. Named covers only characters that have a name, so anything without one falls back to the decimal form.
The HTML decoder turns entities back into readable text. For URLs use the URL encoder instead, and to tidy up the markup itself there is the HTML formatter.