String Escape & Unescape

Escape a string for the context you are about to put it in, or strip escaping from something you received.

Result
What this context requires

There is no such thing as "escaped"

The same string needs five different treatments depending on where it goes. A double quote is harmless inside JSON element content but must be written " in an HTML attribute and doubled as "" in a CSV field. An ampersand means nothing to JavaScript and starts an entity reference in HTML.

This is why "escape everything on the way in" is the wrong model and causes so many double-escaping bugs. Store text raw, and escape it at the moment it crosses into a new context. Text that lives in your database should be the actual text; O'Brien stored in a database is a bug waiting to be double-escaped into O'Brien when it is displayed.

ContextCharacters that matterConsequence of getting it wrong
JSON string" \ and control charactersInvalid JSON, parser rejects the whole document
JavaScript string' \ newlines, U+2028Broken script or injected code
HTML text& < >Cross-site scripting
HTML attributethe above plus your quote characterAttribute injection, breaking out of the value
XML text& <, plus ]]>Not well-formed; parse fails entirely
CSV field" , newlineSilently shifted columns on import
SQL literal', and depending on the engine \SQL injection
URL component& = ? % spaceTruncated or misparsed query strings

Escaping is not a defence, it is a correctness measure. For SQL, the correct answer is a parameterised query, not escaping — escaping can be defeated by charset tricks and multi-byte edge cases in ways that binding a parameter cannot. For HTML, prefer a templating engine that escapes by default over remembering to do it yourself. Use escaping for the cases where it genuinely is the mechanism, such as CSV and URLs.

Why the order of replacements matters

Escape & first, always. If you replace < with &lt; first and then escape ampersands, the ampersand you just inserted becomes &amp; and your output reads literally as &lt; on screen. The same trap applies in reverse when unescaping: decode in one pass over the original text, never repeatedly until the output stops changing, because that lets &amp;lt; collapse all the way to < — turning a doubly-escaped harmless string into live markup.

UTF-8 changed the problem, it did not remove it

Encoding issues used to be the main source of escaping bugs. With everything on UTF-8, the remaining traps are narrower but real: characters that look like ASCII but are not (the Unicode minus sign, smart quotes, non-breaking space), line separators such as U+2028 that are legal in JSON and illegal in JavaScript string literals before ES2019, and combining characters that change how a string compares while looking identical.

Frequently asked questions

Should I store text escaped or raw?

Raw, always. Escape when you move the text into a context that needs it. Storing pre-escaped text means every consumer has to know which context it was escaped for, and that is the origin of double-escaped output.

Why does my CSV break when opened in Excel?

Usually a field containing a comma, quote or newline that was not quoted. Excel also guesses types, so values like 1-2 or leading-zero identifiers get mangled regardless of escaping — import with explicit column types rather than double-clicking the file.

Is encodeURIComponent the same as URL escaping?

It is the right function for a single component — a query value or path segment. It is wrong for a whole URL, because it escapes the colon, slashes and question mark that give the URL its structure. Escaping a complete URL needs a different approach entirely.

What about the plus sign in a URL?

Form encoding uses + for a space; percent-encoding uses %20. They are not interchangeable. In a query string, a literal plus must be %2B, or it will be decoded as a space by a form-style decoder.

Privacy. Conversion runs in your browser. Nothing is uploaded, so it is safe to work with real customer data or credentials.