Urgent.News

What's breaking now, across thousands of outlets.

Tech

Decorative Text on the Web: Unicode, Grapheme Clusters, and Platform Compatibility

Decorative text looks simple. Copy a few symbols, add them to a username or bio, and paste the result into a profile. Done. Until the platform rejects the name. Or the character counter says 11 when the user sees one emoji. Or the cursor jumps into the middle of a joined emoji sequence. Or a screen reader announces a row of symbols without explaining what the control does. Emoji, kaomoji, and…

Decorative text might seem simple, but it involves more technical details than meets the eye. Copying a few symbols and pasting them into a username or bio may seem harmless, but platforms can reject the name, the character counter may give incorrect readings, and screen readers may not provide proper context. Emoji, kaomoji, and Unicode symbols are not just decorative elements; they constitute text with specific structure. Tools that deal with decorative text must consider some key Unicode details to function correctly.

The first aspect to understand is that visible characters may not always correspond to a single code point. For instance, in JavaScript, strings are sequences of UTF-16 code units, which differ from Unicode code points, and both differ from the user's perceived characters. Consider the following family emoji: const text = 👨👩👧👦 ; console.log(text.length); // 11 UTF-16 code units console.log(Array.from(text).length); // 7 Unicode code points To a user, it appears as a single visible character.

Unicode refers to this user-perceived unit as an extended grapheme cluster. When building tools that handle decorative text, it is essential to use grapheme clusters for user-facing counts and cursor movements rather than UTF-16 code units.

Several Unicode specifics impact text tools beyond just emoji. Accented letters created from a base letter and a combining mark, flags using regional indicator symbols, skin-tone modifiers, and emoji combined with zero-width joiners all exhibit similar behavior. Unicode’s Text Segmentation specification provides rules for determining these boundaries. The main takeaway is to avoid assuming that string.length corresponds to the number of characters users see.

Next, the definition of "length" varies depending on the task at hand. Depending on the objective, the appropriate count could be UTF-16 code units, code points, or grapheme clusters. A compatibility checker should not rely solely on JavaScript length, as platforms may count characters differently, reject certain scripts, reserve symbols, or apply distinct rules to different fields.

A grapheme-aware counting function for an editor would be a good default, but the count ought to be labeled honestly, explaining that it does not guarantee acceptance across all platforms.

Variation selectors can influence the presentation of symbols. Two forms of a symbol may look different based on the sequence or font but are not identical strings, creating design questions. For example, ♥ and ♥️ may appear differently, and search tools should consider these forms equivalent while copy tools should preserve the original sequence. Normalization may be necessary for comparison but should not alter the copied text.

Zero-width joiners (ZWJ) are invisible but meaningful. They connect visible components without adding visible width, making ZWJ sequences particularly tricky to handle. A naive sanitizer might remove the joiner, converting one emoji into several unrelated emojis, while a naive character counter could count each component separately.

When editing decorative text, it is essential to segment the string into grapheme clusters, move the cursor by cluster where possible, delete a complete cluster instead of an arbitrary code unit range, and preserve valid sequences during copy and export.

Lastly, copying decorative text as real text is crucial rather than capturing a screenshot. The Clipboard API provides a simple way to copy text: async function copyText(value) { try { await navigator.clipboard.writeText(value); return true; } catch { return false; } } However, there are scenarios where a fallback is necessary, such as when permission is denied, the page is not in a secure context, or the action was not triggered by a user gesture.

Providing a fallback that shows the exact text and explains the next steps, along with clear feedback after a successful copy, enhances accessibility and usability.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

Are the Nordics really on fire?

  • Nordic tech scene attracts significant investment.
  • Freya Pratty, Mimi Billing discuss funding landscape.
  • Sifted Summit in London for deeper insights.

More from Friday 28 August →