Get the visual width of a string - the number of columns required to display it in terminals
npx @tessl/cli install tessl/npm-string-width@8.1.0String Width is a JavaScript utility library that calculates the visual width of strings in terminal applications. It accurately accounts for Unicode characters that display at different widths, including fullwidth CJK characters, ANSI escape codes, and emoji sequences, making it essential for CLI tools and terminal applications that need proper text alignment.
npm install string-widthimport stringWidth from 'string-width';For TypeScript with type imports:
import stringWidth, { type Options } from 'string-width';import stringWidth from 'string-width';
// Basic ASCII string
stringWidth('hello world');
//=> 11
// Fullwidth CJK characters (display as 2 columns each)
stringWidth('古');
//=> 2
// Mixed content
stringWidth('hello世界');
//=> 9 (hello=5, 世=2, 界=2)
// ANSI escape codes are stripped by default
stringWidth('\u001B[1m古\u001B[22m');
//=> 2
// With options
stringWidth('±', { ambiguousIsNarrow: false });
//=> 2 (ambiguous character treated as wide)Calculates the visual width of a string - the number of columns required to display it in a terminal.
/**
* Get the visual width of a string - the number of columns required to display it
* @param string - The string to measure
* @param options - Configuration options
* @returns The visual width in columns
*/
function stringWidth(string: string, options?: Options): number;The function handles:
Usage Examples:
import stringWidth from 'string-width';
// Edge cases and special characters
stringWidth(''); // => 0 (empty string)
stringWidth('\t'); // => 0 (tab ignored by design)
stringWidth('a\tb'); // => 2 (tab doesn't count)
stringWidth('\n'); // => 0 (newline is control char)
stringWidth('你好'); // => 4 (2 chars × 2 width each)
stringWidth('バ'); // => 2 (halfwidth + dakuten)
stringWidth('👨👩👧👦'); // => 2 (family emoji sequence)
stringWidth('🇺🇸'); // => 2 (flag emoji sequence)
stringWidth('👋🏽'); // => 2 (emoji with skin tone)
// Zero-width and combining characters
stringWidth('e\u0301'); // => 1 (combining diacritical mark)
stringWidth('\u200B'); // => 0 (zero-width space)
stringWidth('\u200C'); // => 0 (zero-width non-joiner)
stringWidth('\u200D'); // => 0 (zero-width joiner)
// Non-string inputs return 0
stringWidth(123); // => 0
stringWidth(null); // => 0
stringWidth(undefined); // => 0
// ANSI escape codes
const redText = '\u001B[31mRed\u001B[0m';
stringWidth(redText); // => 3 (ANSI codes stripped)
stringWidth(redText, { countAnsiEscapeCodes: true }); // => 11 (codes counted)
// Ambiguous characters
stringWidth('±§©®'); // => 4 (treated as narrow by default)
stringWidth('±§©®', { ambiguousIsNarrow: false }); // => 8 (treated as wide)Configuration options for controlling width calculation behavior.
interface Options {
/**
* Count ambiguous width characters as having narrow width (count of 1)
* instead of wide width (count of 2).
*
* Ambiguous characters behave like wide or narrow characters depending
* on context. If context cannot be established reliably, they should
* be treated as narrow characters by default.
*
* @default true
*/
readonly ambiguousIsNarrow?: boolean;
/**
* Whether ANSI escape codes should be counted towards the width.
* By default, ANSI codes are stripped and don't affect width calculation.
*
* @default false
*/
readonly countAnsiEscapeCodes?: boolean;
}Option Examples:
import stringWidth from 'string-width';
// Ambiguous character handling
const ambiguous = '±';
stringWidth(ambiguous); // => 1 (narrow)
stringWidth(ambiguous, { ambiguousIsNarrow: false }); // => 2 (wide)
// ANSI escape code handling
const colored = '\u001B[31mHello\u001B[0m';
stringWidth(colored); // => 5 (codes stripped)
stringWidth(colored, { countAnsiEscapeCodes: true }); // => 13 (codes counted)
// Combined options
stringWidth('±\u001B[31mTest\u001B[0m', {
ambiguousIsNarrow: false,
countAnsiEscapeCodes: true
}); // => 14 (± as wide + ANSI codes counted + Test)