A form says there are twenty characters available. Then someone enters an emoji and the counter drops by two. The implementation might be doing exactly what it was written to do. The explanation on the screen is still confusing.
I would rather settle the meaning of a character before choosing the validation library. JavaScript's length counts UTF-16 code units. Spreading a string counts code points. Neither operation necessarily counts the clusters a person sees as individual characters.
One input, several reasonable numbers
Consider A๐B. Its JavaScript length is four; it contains three code points and three grapheme clusters. Now consider e\u0301: an e followed by a combining accent. That representation has two code units and two code points, but one grapheme cluster. A storage limit measured in UTF-8 bytes introduces another unit.
const value = 'A๐B';
const segmenter = new Intl.Segmenter('en', {
granularity: 'grapheme'
});
console.log(value.length); // 4
console.log([...value].length); // 3
console.log([...segmenter.segment(value)].length); // 3This example was checked in Node.js v26.0.0. The Intl.Segmenter reference describes the segmentation API. A server in another language needs an equivalent rule; copying the number twenty into two validators does not establish agreement.
Normalization is a separate decision. The composed and decomposed forms of an accented character can compare differently before normalization. That does not mean every field should silently rewrite the original input. A display name, a search key and an identifier can have different preservation requirements.
The counter is part of the contract
If the product promises twenty visible clusters, its live counter and server validation should use that meaning. If storage imposes a byte limit, explain the additional constraint rather than pretending it is the same limit. Trimming spaces also changes what is counted, so the order matters.
My small test set would include an ordinary name, a supplementary-plane emoji, a combining sequence, a joined emoji, surrounding spaces and an empty value. I would keep the exact strings beside the expected accept/reject results. That is a proposed product test set, not evidence that a particular signup flow has passed it.
The interesting bug is often in the sentence above the field. A validator can be internally consistent while the product makes a different promise.
ํ๊ตญ์ด ๊ธ: ์ด๋ฆ์ 20์๊น์ง๋ผ๋๋ฐ, ์ด๋ชจ์ง ํ๋๋ ๋ช ์์ผ๊น
