Data & APIs

Unicode Code Points vs UTF-16 Code Units vs Graphemes

Understand why JavaScript string length differs from visible character count for emoji and combining marks.

Photorealistic editorial photo for Unicode Code Points
Data & APIs Β· Practical ideas for your next build

Counting characters is ambiguous. A user sees symbols, Unicode assigns code points, and JavaScript stores strings as UTF-16 code units. A single visible symbol can occupy multiple code points and several code units. Choose the measurement that matches your task before applying limits or truncation.

Know what string length counts

JavaScript length counts UTF-16 code units. Many familiar letters use one unit; a supplementary-plane emoji uses two. Iterating a string with for...of works by code point, so it handles a surrogate pair together. However, code points still do not always correspond to user-perceived characters. A letter plus a combining accent contains multiple code points even when it looks like one letter.

Use grapheme segmentation for visible editing

Emoji sequences can include skin-tone modifiers, variation selectors, and zero-width joiners. Cutting such a sequence in the middle may produce an unintended symbol. Intl.Segmenter with grapheme granularity is useful for cursor-like operations and user-facing truncation in supported environments. Keep byte limits separate: an API or database may enforce UTF-8 bytes rather than any character count.

Normalize only with a clear purpose

Two visually identical strings may have different code-point sequences, such as an accented letter stored as one precomposed code point or as a base letter plus a mark. Unicode normalization can help comparison, but compatibility normalization may change distinctions that matter to your application. Do not normalize passwords or signed payloads casually. Inspect escaped output when debugging invisible differences and document which normalization form your system expects.

Worked example

EXAMPLE
"πŸ‘‹".length // 2 code units
[..."πŸ‘‹"].length // 1 code point
[..."é"].length // 2 code points

Is Array.from(text).length a visible character count?

It counts code points, not grapheme clusters. Combined emoji and accented sequences can still be counted as multiple items.

Reference and further reading

Read the official documentation β†—