SuperAPI AI Directory

cjk-text-and-input

Frontend & websites

View repository

Updated 10-16 09:30

About this skill

CJK text & IME input

Two families of bugs that English-only testing never surfaces: line breaking (CJK text wraps differently) and IME composition (characters are composed across multiple keystrokes, so key events lie).

This skill is East-Asian glyph rendering + input. For the broader multi-language copy layer — text expansion breaking layout, CLDR plural categories, Intl number/date/currency formatting, RTL and lang/dir markup — use i18n-copy-and-layout.

Line breaking

  • East Asian text lines can break between almost any two characters by default (UAX #14 ideographic line-breaking class; UAX #14 itself notes Korean is commonly tailored to space-based breaking) — in CSS, English-style word integrity for Korean is opt-in via word-break: keep-all, not the default.
  • Korean: word-break: keep-all prevents intra-word breaks for CJK text so space-separated Korean words wrap as units (MDN: "Word breaks should not be used for Chinese/Japanese/Korean (CJK) text"). Pair with overflow-wrap: break-word as the escape hatch for long unbreakable tokens (URLs).
  • word-break: break-all solves the opposite problem — inserting breaks between any two characters of non-CJK text to prevent overflow (CJK behavior is unchanged by it, per MDN); don't apply it to body text in mixed-language UIs.
  • line-break: strict|loose tunes Japanese/Chinese punctuation-adjacent breaking (kinsoku); it does not control Korean word integrity — that's keep-all.
  • Headlines/buttons: test with real Korean copy — label widths differ wildly from English and mid-word breaks read as typos to native speakers. W3C klreq (Korean Layout Requirements) is the canonical reference for Korean typography rules.

IME composition (the part that breaks controlled inputs)

  • IMEs compose text across keystrokes; the DOM fires compositionstart → compositionupdate* → compositionend (MDN CompositionEvent).

  • During composition, key events are unreliable for shortcuts: keydown fires with KeyboardEvent.isComposing === true, and legacy browsers/engines report keyCode 229 (UI Events spec documents 229 as the IME-processing code). The classic bug: pressing Enter to commit the IME buffer ALSO triggers the form's Enter handler — submitting half-composed text. Guard:

    input.addEventListener('keydown', (e) => {
      if (e.isComposing || e.keyCode === 229) return; // IME is composing — not a command
      if (e.key === 'Enter') submit();
    });
    
  • Controlled inputs (React etc.): transforming/filtering value on every change while isComposing breaks the composition buffer (characters duplicate or split, e.g. Hangul jamo separation) — community-documented across React issue threads rather than any spec, but consistently reproducible. Apply sanitization/uppercase/masking on compositionend or blur, not mid-composition.

  • Search-as-you-type: each composition update fires input events with partially composed Korean syllables, for example ㅅ → 스 → 슼 → 스키 → 스킬 (successive input states while typing the word skill). Debouncing alone still queries invalid intermediate states; gate dispatch on compositionend (plus a normal path for non-IME input).

  • Browser order differences exist between engines for compositionend vs the final input event — never assume one fixed sequence; branch on event.isComposing rather than event order.

Counting and slicing

  • String.length counts UTF-16 code units, not user-perceived characters. Hangul syllables in NFC are 1 unit, but decomposed jamo are 2-3 (NFD; also file names from macOS HFS+-era tooling — HFS+ stored names in a frozen canonical decomposition similar to, but not identical to, standard NFD); emoji are 2+. For user-facing length limits and cursor-safe slicing use Intl.Segmenter (grapheme granularity) and normalize (.normalize('NFC')) before comparing strings from mixed sources. Feature-detect Intl.Segmenter; for older WebViews or browsers, fall back to a tested grapheme-splitter library or a conservative "validate after input, do not slice mid-string" policy rather than pretending String.length is a character count.

PR-worthiness gate

Require a real CJK string or IME sequence and a user-visible failure: a broken composition buffer, premature shortcut/submit, incorrect grapheme limit, or layout that makes actual copy unreadable. Add the smallest native-input or rendered-text regression.

Reject weak findings: keyCode === 229 used only as a compatibility guard, String.length on protocol bytes or internal identifiers, a generic narrow container with no CJK reproduction, or translation expansion that belongs to i18n-copy-and-layout.

Output shape

Report the language/input method, composition or layout sequence, event and rendered evidence, smallest guard/style/segmentation fix, browser or WebView matrix, and the regression that uses real CJK text.

Sources