Escaping and Unescaping Special Characters in JavaScript

In Brief
Escaping is context‑specific: HTML text and attributes, URLs, JavaScript and JSON strings, and regular expressions each have their own rules. Use the encoding required by the exact output context; a value escaped for one context may be unsafe in another. Escaping is not sanitisation, and unescaping or decoding can reintroduce syntax that must not be treated as trusted content.
A string that is safe in one place may be wrong or dangerous in another. HTML, JSON, a URL component, and a JavaScript string literal each have different escaping rules. Problems begin when one generic 'escape' helper is expected to cover all of those contexts.
What are Special Characters?
Special characters are characters that have a specific meaning in certain contexts, such as programming, markup languages, or regular expressions. Some examples include:
\nfor a newline.\tfor a tab.<and>in HTML.\as an escape character in JavaScript.
In JavaScript, the backslash (\) is used as an escape character to indicate that the character following it should be treated differently. For example:
const escapedString = "This is a \"quote\".";
console.log(escapedString); // Output: This is a "quote".Escaping Special Characters
Escaping special characters ensures that they are treated as literal values rather than having their usual meaning. This is really important when dealing with user‑generated input, HTML content, or regular expressions, especially when it comes to security and attempting unauthorised access to your application or its data.
Let's talk through some common scenarios.
Escaping Characters in Strings
In JavaScript, you can escape characters using a backslash (\). For example:
const stringWithNewline = "First line\nSecond line";
console.log(stringWithNewline);
// Output:
// First line
// Second line
const stringWithBackslash = "A backslash: \\";
console.log(stringWithBackslash); // Output: A backslash: \Escaping HTML
For HTML text and ordinary, quoted attributes such as title, this helper encodes characters that would otherwise be read as markup. It does not make a value safe in an event‑handler attribute such as onclick, or validate a URL used in href or src. Prefer textContent when all you need is visible text:
function escapeHTML(input) {
return input
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
const userInput = "<script>alert('XSS');</script>";
console.log(escapeHTML(userInput)); // Output: <script>alert('XSS');</script>Escaping in Regular Expressions
In regular expressions, characters like . and * have special meanings too. You need to escape them to match them literally:
const pattern = /\./g; // Matches a literal period (.)
const result = "1.2.3".replace(pattern, "-");
console.log(result); // Output: 1-2-3Unescaping Special Characters
Unescaping is the reverse process, converting escaped characters back into their original form. This is often required when processing escaped data and can be a little more involved than escaping it in the first place might have been.
Unescaping HTML
For a small, trusted string of HTML entities, DOMParser can decode them whilst parsing an HTML document. This is a parsing demonstration, not a sanitiser: markup in the input becomes document structure, and resource elements may cause network requests even in a detached document. Don't pass arbitrary untrusted HTML to it as an escaping shortcut:
function unescapeHTML(input) {
const parser = new DOMParser();
const doc = parser.parseFromString(input, "text/html");
return doc.documentElement.textContent;
}
const escapedHTML = "<div>Hello</div>";
console.log(unescapeHTML(escapedHTML)); // Output: <div>Hello</div>Unescaping Strings
The next helper recognises just two sequences: \n and \t. It demonstrates replacement, not general JavaScript‑string decoding; it doesn't handle escaped backslashes, quotes, Unicode escapes or combinations of them. For data serialised as valid JSON, use JSON.parse() at the matching boundary instead:
function unescapeString(input) {
return input.replace(/\\n/g, "\n").replace(/\\t/g, "\t");
}
const escapedString = "Line1\\nLine2";
console.log(unescapeString(escapedString)); // Output: Line1
// Line2Practical Applications
- Preventing XSS: HTML encoding helps in text and ordinary quoted attributes. Event handlers and URL‑valued attributes need different treatment; encoding alone does not make them safe.
Data Serialisation
: Properly escaping and unescaping data is essential for JSON or CSV parsing.Regex Patterns
: Escaping ensures special characters in strings don't interfere with regular expressions.
Escaping is Not Sanitising
Escaping makes text safe for a particular output context. It is not the same as deciding whether the original input is trustworthy. If user input may contain unsafe HTML, the decision is not just "escape or unescape"; it is whether to reject it, sanitise it, encode it or render it as plain text.
That distinction is important because the safe version for one context can be unsafe in another. A string escaped for HTML text is not automatically safe inside a URL, a JavaScript string, a CSS selector, or a regular expression.
Match the Escaping to the Output
For HTML text, encode characters such as <, >, & and quotes when needed. For regular expressions, escape characters that have pattern meaning. For URLs, use URL encoding rather than HTML entities. Mixing those contexts is where subtle bugs and security issues tend to appear.
Wrapping Up
Key Takeaways
- Special characters like
\nand\thave specific meanings in JavaScript and must be escaped to be used literally. - Escaping for an HTML text context prevents user input from being interpreted as markup; other contexts need their own encoding.
- Unescaping is often necessary to process escaped data into its original form.
- Use the parser or encoder designed for the format, and treat decoded content as untrusted until the destination has been checked.
Choose the encoder for the destination: JSON.stringify for JSON data, encodeURIComponent for a URL component, and the DOM's text APIs for visible text. Decode only at the matching boundary. Escaping is contextual, so a value being safe in one representation says nothing about the next one.