String.prototype.normalize()
The answer to "these two strings look the same but are not equal". An accented letter can be stored as one code point or as a base letter plus a combining mark, and === cannot tell you which you have.
Demo
The output lists the code points in hex, because that is the only way to see what happened — every form of 'é' renders identically on screen. NFC gives a single code point e9. NFD gives two: 65, a plain letter e, followed by 301, a combining acute accent. Both display as é and they are NOT ===. The last two cases show the K forms going further: the fi ligature becomes two ordinary letters, and the circled digit ① becomes a plain 1. That is useful for search and destructive for display — NFKC discards the distinction permanently.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| form | string | no ('NFC') | One of 'NFC', 'NFD', 'NFKC', 'NFKD'. The C forms compose, the D forms decompose; the K forms additionally fold compatibility characters, which loses information. |
Return value
string — The string converted to the requested Unicode normalization form. Default is NFC, the composed form most systems expect.
Common patterns
const key = input.normalize('NFC');
const bare = s.normalize('NFD').replace(/\p{Diacritic}/gu, '');
a.localeCompare(b, undefined, {sensitivity: 'base'}) === 0;
Examples
Pitfalls
'\u00e9' === 'e\u0301'
'\u00e9'.normalize() === 'e\u0301'.normalize()
'x\u00b2'.normalize('NFKC')
'x\u00b2'.normalize('NFC')
'\u00e9'.normalize('NFD').length
const t = s.normalize('NFC'); t.indexOf(x);
'\u00e9'.normalize('NFD') === 'e'
'\u00e9'.normalize('NFD').replace(/\p{Diacritic}/gu, '') === 'e'
When to use
- Before comparing, hashing or storing text from users or files
- Deduplicating names, tags or filenames
- Building a search key, with the K forms
- As the first step of accent stripping
- You only need a case-insensitive compare → toLowerCase
- You want proper linguistic comparison → localeCompare with sensitivity
- Storing display text → never store the K forms
- Pure ASCII data → normalisation is a no-op, skip it
Notes
FAQ
NFC for anything you store or transmit — it is the web default, what most databases expect, and the shortest. NFD when you need to inspect or remove combining marks. The K forms only for building a comparison key you throw away afterwards.
store(input.normalize('NFC')); searchKey = input.normalize('NFKC').toLowerCase();