String.prototype.normalize()

Returns the Unicode Normalization Form of a string so equivalent spellings compare equal.

Signature
normalize()
normalize(form)
  • Added in JavaScript ES2015

Parameters

ParameterTypeDescription
$formoptional"NFC" | "NFD" | "NFKC" | "NFKD"= "NFC"The normalization form to apply. NFC is canonical decomposition followed by canonical composition; NFD is canonical decomposition; NFKC and NFKD are the compatibility equivalents.

Return value

stringA new string containing the Unicode Normalization Form of the calling string.

Errors

Throws a RangeError if form is not one of "NFC", "NFD", "NFKC", or "NFKD".

Unicode can spell the same visible text more than one way. é may be the single code point U+00E9, or the letter e followed by U+0301 COMBINING ACUTE ACCENT. They render identically and === says they are different. normalize() rewrites a string into one canonical spelling so the comparison works.

Choosing a form

  • NFC — composes to the shortest form. The default, and what you want for storage, keys, and equality.
  • NFD — decomposes into base letters plus combining marks. Useful as a first step in stripping accents.
  • NFKC / NFKD — additionally fold compatibility characters: fi becomes fi, ① becomes 1, full-width forms become ASCII. Lossy, but good for search indexes.

When to reach for it

Normalise at the boundary — text pasted by a user, filenames from macOS (which hands out NFD), data from a third-party API — then compare and store the normalised value. Normalising on every comparison instead invites the bug where a stored key and a fresh input differ invisibly.

The classic accent-stripper is str.normalize("NFD").replace(/\p{Diacritic}/gu, ""). It works because NFD splits the mark off as its own code point.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Reconcile a filename read from macOS with the same name typed by a user
  • Build accent-insensitive search keys by normalizing to NFD and stripping diacritics
  • Fold full-width and ligature characters before indexing text with NFKC
  • De-duplicate names pasted from different sources that look identical

Frequently asked questions

Why do two identical-looking strings compare as unequal in JavaScript?

They are almost certainly different Unicode spellings of the same text — a precomposed accented letter versus a base letter plus a combining mark. Call normalize("NFC") on both before comparing, and store the normalized form so the mismatch cannot recur.

What is the difference between NFC and NFD?

NFC composes characters into the shortest precomposed form and is the right default for storage and equality, while NFD decomposes them into base characters plus combining marks. Reach for NFD when you want to inspect or remove the marks themselves.

How do I remove accents from a string in JavaScript?

Use str.normalize("NFD").replace(/\p{Diacritic}/gu, "") — NFD splits each accent into its own code point and the Unicode-aware regex deletes them. This handles Latin scripts well but does not transliterate other writing systems.

More examples

Stripping accents via NFD

NFD separates each accent into its own combining code point, which the regex then deletes. All three spellings of the name collapse to one search key, so the Set reports a single entry. Cyrillic is unaffected because those letters carry no separable marks.

Example · javascript
const strip = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "");

console.log(strip("café"));
console.log(strip("Ñandú"));
console.log(strip("Дежавю"));

const names = ["Zoë", "Zoe", "Zoé"];
console.log(new Set(names.map((n) => strip(n).toLowerCase())).size);

Compatibility forms fold more aggressively

NFC leaves the fi ligature intact because the two spellings are not canonically equivalent, while NFKC rewrites it as plain "fi". Circled digits and full-width Latin also fold to ASCII. An unrecognised form name is a RangeError, not a silent fallback to NFC.

Example · javascript
console.log("fi".normalize("NFC"), "|", "fi".normalize("NFKC"));
console.log("①".normalize("NFKC"));
console.log("Hello".normalize("NFKC"));

try {
  "x".normalize("NFX");
} catch (err) {
  console.log(err.name);
}

Discussion

  • Be the first to comment on this lesson.