HTML Special Characters in Forms, URLs, and JSON
Published March 15, 2025
The five reserved HTML characters
Five characters have special meaning in HTML and must be escaped when you want to display them as literal text:
| Character | Entity | Why it's reserved |
|---|---|---|
| < | < | Opens an HTML tag |
| > | > | Closes an HTML tag |
| & | & | Starts an entity reference |
| " | " | Delimits attribute values |
| ' | ' | Alternative attribute delimiter |
Escaping in HTML body text
Inside element content, you must escape < and &. It's good practice to escape > too, although browsers generally handle it unescaped. If you write <p>5 < 10</p>, the browser displays “5 < 10” correctly instead of trying to parse a tag.
Escaping in HTML attributes
Inside attribute values, you must escape the quote character that matches the delimiter. If the attribute uses double quotes, escape " as ". Always quote your attribute values — unquoted attributes are a common source of XSS vulnerabilities because spaces or other characters can break out of the value.
<!-- Safe: quotes are escaped -->
<input value="He said "hello"">
<!-- Dangerous: unquoted attribute -->
<input value=user_input>Escaping in JavaScript strings
In inline <script> blocks, the HTML parser takes precedence. The sequence </script> appearing anywhere — even inside a string literal — will close the script element. To avoid this:
- Split the closing tag:
"</" + "script>" - Use Unicode escapes:
"\u003c/script>" - Or better yet, avoid inline scripts and use external files or
JSON.stringify()for dynamic data
Escaping in JSON
JSON requires escaping double quotes (\"), backslashes (\\), and control characters. Newlines become \n, tabs become \t. Any character can be represented with a Unicode escape: \u00A9 for ©.
Always use JSON.stringify() to generate JSON programmatically. Manual string building is a recipe for malformed output and injection bugs.
Escaping in URLs
URLs use percent-encoding for characters outside the unreserved set. A space becomes %20, an ampersand becomes %26. In JavaScript:
encodeURIComponent()encodes a single query parameter value (escapes&,=,?, etc.)encodeURI()encodes a full URI (preserves:,/,?,&)
When building URLs with user input, always encode parameter values with encodeURIComponent() to prevent parameter injection.
Preventing XSS
Cross-site scripting (XSS) occurs when an attacker injects malicious scripts through unescaped user input. Key defenses:
- Never insert user input as raw HTML. Use
textContentinstead ofinnerHTML - Use framework auto-escaping — React, Vue, Angular, and Svelte all escape interpolated values by default
- Set a Content Security Policy header to restrict script sources
- Sanitize HTML if you must accept rich text (use a library like DOMPurify, never regex)
Common mistakes
- Double-encoding: escaping an already-escaped string turns
&into&amp;, which displays as “&” instead of “&” - Forgetting attribute escaping: a user's name containing a quote can break out of an attribute and inject HTML
- Trusting client-side sanitization: always sanitize on the server too, since client-side checks can be bypassed
- Mixing encoding contexts: HTML-escaping a value that goes into a URL, or URL-encoding a value that goes into HTML, produces gibberish