Unicode-aware terminal cell width engine: grapheme cluster boundaries + terminal-style cluster width.
npm install uc-widthUnicode-aware terminal cell width engine that measures grapheme clusters under terminal conventions, plus a stateful stepper for streaming text.
``sh`
npm i uc-width
ESM: import { ucWidth } from "uc-width" const { ucWidth } = require("uc-width")
CJS: (no default export)
Stateful stepper for streaming text. Reports:
- shouldJoin: whether cp continues the previous grapheme clusterclusterWidth
- : current cluster width (0–2) after consuming cpstate
- : opaque state to feed into the next call
`js
// Cluster a mixed string into: [ [codePoints[], width], ... ]
import { ucWidthStep, ucWidthOptions } from "uc-width";
const str = "A中ä⌚︎⌚️👨🌾";
const opt = ucWidthOptions();
let state;
const out = [];
for (const ch of str) {
const cp = ch.codePointAt(0);
const res = ucWidthStep(cp, opt, state);
if (!res.shouldJoin) out.push([[], 0]);
out.at(-1)[0].push(cp);
out.at(-1)[1] = res.clusterWidth;
state = res.state;
}
console.log(JSON.stringify(out));
// => [[[65],1],[[20013],2],[[97,776],1],[[8986,65038],1],[[8986,65039],2],[[128104,8205,127806],2]]
`
Simple calculator for the width of an entire string.
`js
import { ucWidth } from "uc-width";
const str = "A中ä⌚︎⌚️👨🌾";
console.log(ucWidth(str));
// => 9
`
Defaults: ucWidthOptions({ nul: 0, control: 0, ambiguous: 1, vs15: 1 }).
- nul / control: whether control chars should consume a cell (0 or 1).ambiguous
- : Western terminals typically use 1; some CJK environments prefer 2.vs15
- : depends on whether your terminal supports (or wants) VS15 narrowing.
- Unicode tables are derived from Unicode 17.0.0.
- Width policy is aligned with the wcwidth ecosystem and tested against Python wcwidth.ucs-detect
- Repo includes an xterm.js Unicode provider demo plus a harness (npm run xterm-detect).
Terminal cell width is a terminal convention rooted in wcwidth-style column heuristics (see Kuhn’s wcwidth.c`). Many modern terminals are grapheme-aware, but width policy remains elusive (kitty RFC #8533, Ghostty writeup). There is no Unicode-sanctioned width standard; however, discussion continues (e.g. L2/23-107, TTWG report).