README.md

May 31, 2026 Β· View on GitHub

ansis
Make terminals a little more colorful 🌈

[ANSI S]tyles

npm Test codecov downloads install size

Ansis demo

ANSI color library for use in terminals, CI environments, and Chromium-based browsers.
Ansis is focused on small size and speed while providing rich functionality and handling edge cases.

// Named imports - for cleaner, more readable code
import { red, cyan, bold, hex, rgb } from 'ansis';

// Clean chained syntax with template literals - no extra parentheses
console.log(bold.bgRed` FAIL `);

// Nested templates - no string concatenation needed
console.log(red`βœ– Error: ${cyan`file.js`} not found`);

// Truecolor: hex and rgb
console.log(hex('#FF75D1').bold`Pink`);
console.log(rgb(224, 17, 95).italic`Ruby`);

πŸ”— Shortcuts

πŸš€ Getting Started πŸ“Œ Ansis vs styleText() πŸ”„ Migrating from βš–οΈ Alternatives βœ… Compare features

πŸ’» CLI Environment πŸ§ͺ CLI Testing βš™οΈ Compatibility πŸ”§Troubleshooting

πŸ”” Upgrading to v4 Β· New features Β· Breaking changes

⭐️ Star History

✨ Highlights

🎨 Colors - 16 · 256 · Truecolor (hex/rgb) · Named colors (orange, pink ...)
✍️ Syntax - Chained · Template literals · Nested templates
βš™οΈ Works  - ESM Β· CJS Β· TS Β· Node 10+ Β· Bun Β· Deno Β· CI Β· Chromium browsers
🧠 Smart  - Auto color detection Β· Fallback (truecolor β†’ 256 β†’ 16 β†’ b&w) Β· NO_COLOR Β· FORCE_COLOR
πŸ“¦ Tiny   - 5.8 kB Β· Drop-in replacement for Chalk (44 kB)

⚑ Performance

Ansis is the fastest when using 2 or more styles, which is the common real-world use case.

Library1 style2+ styles
ansis60M ops/secπŸ† 60M ops/sec
picocolorsπŸ† 109M ops/sec58M ops/sec
chalk55M ops/sec47M ops/sec
util.styleText0.5M ops/sec0.5M ops/sec

πŸ“Š Full benchmarks β†’

πŸ’‘ Features

🎨 Colors & Styles

✍️ Syntax

πŸ› οΈ Utilities

  • Strip ANSI codes: ansis.strip(red('text')) β†’ plain 'text'
  • Hyperlink: blue.link('https://...', 'Click here'), link('https://...')
  • Raw escape codes: open / close - `${red.open}Error${red.close} file not found`

πŸ’» Environment

βš™οΈ Compatibility

🎯 You might also like

  • ansilight - Truecolor syntax highlighter for the terminal with 256 highlight.js themes
  • flaget - CLI argument parsing. A smaller (5 kB) and faster alternative to yargs-parser (85 kB)

βš–οΈ Alternatives

chalk, picocolors, colorette, kleur, ansi-colors, kolorist, cli-color, colors-cli, colors.js, tinyrainbow

Since Node.js 22 supports ANSI styling natively via util.styleText(), it is recommended for simple use cases where 16 colors are enough and top performance is not critical. See styleText() limitations.

βœ… Compare features πŸ“Š Benchmarks 🧩 Handling edge cases

Install

npm install ansis

For Node.js 10–12+ use special build npm install ansis@node10

Usage

ESM

import ansis, { red, bold, fg, hex, rgb } from 'ansis';

CJS

const ansis = require('ansis');
const { red, bold, fg, hex, rgb } = require('ansis');

Chained syntax

All colors, styles and functions are chainable. Each color or style can be combined in any order.

import { red, bold, hex } from 'ansis';

red.bold`text`;
hex('#FF75D1').bgCyan.bold`text`;
bold.hex('#FF75D1').bgCyan`text`;

Template literals

Omit parentheses to keep your code clean:

import { red, yellow, green } from 'ansis';

red`Error`; // no parentheses
red`Red ${yellow`Yellow ${green`Green`} Yellow`} Red`; // deep nested templates

Escape sequences work exactly as in regular strings:

red`Hello\nWorld`; // two lines in red
red`prev\\next`;   // one line: prev\next

↑ top

ANSI Styles

dim bold italic underline strikethrough inverse visible hidden reset

ANSI 16 colors

There are 16 basic colors: 8 standard and 8 bright variants.

ExampleColorBackgroundBright ExampleBright ColorBright Background
blackbgBlackgraybgGray
redbgRedredBrightbgRedBright
greenbgGreengreenBrightbgGreenBright
yellowbgYellowyellowBrightbgYellowBright
bluebgBlueblueBrightbgBlueBright
magentabgMagentamagentaBrightbgMagentaBright
cyanbgCyancyanBrightbgCyanBright
whitebgWhitewhiteBrightbgWhiteBright

ANSI 256 colors

  • Foreground: fg(code) - chalk.ansi256(code) equivalent
  • Background: bg(code) - chalk.bgAnsi256(code) equivalent
import { bold, fg, bg } from 'ansis';

fg(96)`Bright Cyan`;
bg(105).fg(96)`Cyan text on magenta background`;
bold.fg(96).underline`Bold underline Bright Cyan`;

256 color codes

ANSI 256 colors

See ANSI color codes.

Fallback

If a terminal supports only 16 colors then ANSI 256 colors will be interpolated into base 16 colors.

Fallback ANSI 256 colors to 16 colors

Truecolor

  • Foreground: hex() rgb()
  • Background: bgHex() bgRgb()
import { bold, hex, rgb, bgHex } from 'ansis';

hex('#E0115F').bold`Bold Ruby`;
rgb(224, 17, 95).italic`Italic Ruby`;
bold.hex('#E0115F').bgHex('#96C')`Ruby text on amethyst background`;

See also named truecolors.

Fallback

Ansis automatically interpolates to the best available color level.

Truecolor β†’ 256 colors β†’ 16 colors β†’ no colors (b&w)

output

↑ top

Named truecolors

Register any hex color as a named style via extend(). Background methods bg* are generated automatically.

import { Ansis } from 'ansis';

const myTheme = {
  orange: '#ffa500',
  pink:   '#ffc0cb',
};

const color = new Ansis().extend(myTheme);

color.orange.bold`orange bold`;       // extended first in chain
color.bgOrange`orange background`;    // auto-generated bg tag
color.pink`pink foreground`;
color.bgPink`pink background`;        // auto-generated bg tag
color.red`built-in red still works`;  // built-in remains intact

Warning

For extended styles, create a new Ansis instance and call extend() on it.

Tip

For all CSS named colors use css-color-names package.

output

Open in StackBlitz

Example: extend with CSS color names

import { Ansis } from 'ansis';
import colorNames from 'css-color-names'; // { pink: '#ffc0cb', orange: '#ffa500', ... }

const color = new Ansis().extend(colorNames);

color.pink('Pink foreground');
color.bgPink('Pink background'); // auto-generated bg

Tip

Need help picking a color name? Try the Name that Color tool - paste a hex and get its closest color name.

OSC 8 hyperlinks are now supported by many terminal emulators.

Use link(url, text?) to create a terminal hyperlink. If text is omitted, the URL itself is used as the visible label.

  • link(url, text) - link URL + optional link text
  • link(url) - URL as both target and text
import { blue, link } from 'ansis';

link('https://example.com'); //  URL and text are the same
blue.underline.link('https://example.com', 'Click here');

Important

Call link() last in the chain:

blue.underline.link(...); // βœ…
blue.link(...).underline; // ❌

Warning

In unsupported terminals text is shown without a link.


↑ top

Color support

Ansis automatically detects the supported color level:

  • 0 – No color
  • 1 – Basic ANSI (16 colors)
  • 2 – Extended ANSI (256 colors)
  • 3 – Truecolor (16 million colors)

Check the detected level at runtime:

import ansis from 'ansis';

console.log(ansis.level);         // 0 | 1 | 2 | 3
console.log(ansis.isSupported()); // true -> level > 0 (at least 16 colors supported)

Create an Ansis instance directly when you need to override color detection:

import { Ansis } from 'ansis';

const noColor    = new Ansis(0);  // always plain text, no ANSI codes
const basicColor = new Ansis(1);  // 16 colors; hex/rgb fall back to nearest
const autoColor  = new Ansis();   // auto-detect using globalThis

console.log(noColor.red`foo`);                  // plain text, no ANSI codes
console.log(basicColor.hex('#FFAB40')`Orange`); // falls back to yellowBright

The constructor also accepts a mock globalThis object to control auto-detection in custom runtimes:

const color = new Ansis({
  process: {
    env: { FORCE_COLOR: '1' }, // COLORTERM, TERM, CI, NO_COLOR, FORCE_COLOR
    argv: ['node', 'app.js'],  // --no-color, --color
    stdout: { isTTY: false },
    platform: 'linux',
  },
});

console.log(color.level); // 1
Example: disable colors via custom CLI flag, e.g. --save-to-log
import { Ansis } from 'ansis';

/**
 * @param  {boolean} noColors Disable colors for non-terminal output.
 * @return {Ansis} Default or custom instance
 */
function safeAnsis(noColors) {
  return noColors
    ? new Ansis(0) // disable colors
    : new Ansis(); // auto/detect color support
}

// handle a special CLI flag to disable colors
const ansis = safeAnsis(process.argv.includes('--save-to-log'))

Auto-detection

Ansis detects color support from the runtime environment in this order:

  1. Chromium browser-like runtimes

    • detected first -> truecolor
  2. COLORTERM (some terminals set it even when output is not TTY)

    • truecolor or 24bit -> truecolor
    • ansi256 -> 256 colors
    • ansi -> 16 colors
  3. CI environment (not TTY)

    • GitHub Actions -> truecolor
    • other CI environments -> 16 colors
  4. Terminal

    • no TTY -> no colors
    • TERM=dumb -> no colors
    • PM2 and Next.js non-TTY runtimes -> color output
  5. Windows

    • Windows terminals since Windows 10 build 14931 (released 2016) -> truecolor
  6. 256-color terminals

    • known 256-color terminals -> 256 colors
  7. Fallback

    • unknown terminals -> 16 colors
Supported terminals and CI environments
TerminalANSI 16
colors
ANSI 256
colors
True
Color
env.
TERM
env.
COLORTERM
Specifically ENV variables
Azure CIβœ…βŒβŒdumbTF_BUILD
AGENT_NAME
GitHub CIβœ…βœ…βœ…dumbCI, GITHUB_ACTIONS
GitTea CIβœ…βœ…βœ…dumbCI, GITEA_ACTIONS
GitLab CIβœ…βŒβŒdumbCI, GITLAB_CI
Travis CIβœ…βŒβŒdumbTRAVIS
PM2
not isTTY
βœ…[^1]βœ…[^1]βœ…[^1]dumbPM2_HOME
pm_id
JetBrains TeamCity
>=2020.1.1
βœ…βœ…βŒTEAMCITY_VERSION
JetBrains IDEAβœ…βœ…βœ…xterm-256colorTERMINAL_EMULATOR='JetBrains-JediTerm'
VS Codeβœ…βœ…βœ…xterm-256colortruecolor
Windows
Terminal
βœ…βœ…βœ…[^2]
Windows
PowerShell
βœ…βœ…βœ…[^2]
macOS Terminalβœ…βœ…βŒxterm-256color
iTermβœ…βœ…βœ…xterm-256colortruecolor
Kittyβœ…βœ…βœ…xterm-kittytruecolor
KDE Konsoleβœ…βœ…βœ…xterm-256colortruecolor
  • ^1 Colors supported depends on actual terminal.
  • ^2: The Windows terminal supports true color since Windows 10 revision 14931 (2016-09-21).

See also:

Environment & CLI options

Ansis detects color support automatically, but you can override it with environment variables and CLI flags.

Note

Priority order, from lowest to highest:

  1. auto-detection
  2. NO_COLOR
  3. CLI color flags
  4. FORCE_COLOR

Environment variables

NO_COLOR

Set to any non-empty value (1, true) to disable color output (see no-color.org):

NO_COLOR=1 node app.js

FORCE_COLOR

Force or override color support via environment variable (see force-color.org).

ValueBehavior
0 or falseDisable colors (level 0)
1Force 16 colors (level 1)
2Force 256 colors (level 2)
3Force truecolor (level 3)
true or any other stringAuto-detect, with fallback to 16 colors if detection fails

Important

Ansis differs from the original force-color.org rule in a few cases:

  • FORCE_COLOR=0 disables colors.
    This matches Node.js, but the original force-color.org rule enables colors when the value is a non-empty string, regardless of the actual value.

  • FORCE_COLOR=true and an empty value enable colors.
    This matches Node.js, but the original force-color.org rule ignores an empty string.

COLORTERM

Hint the auto-detected color level using terminal emulator conventions:

ValueLevel
ansi16 colors (level 1)
ansi256256 colors (level 2)
truecolor or 24bitTruecolor (level 3)

CLI flags

Pass --no-color or --color directly to your script:

./app.js              # auto-detect
./app.js --no-color   # disable colors
./app.js --color      # enable colors (useful when piping output)

Note

If multiple CLI color flags are present, the last one wins:

  • --color --no-color -> --no-color
  • --no-color --color -> --color

Quick reference

node app.js                             # auto-detect
node app.js > log.txt                   # no colors (non-TTY)

NO_COLOR=1 node app.js                  # force off
FORCE_COLOR=0 node app.js               # force off

FORCE_COLOR=1 node app.js > log.txt     # force 16 colors
FORCE_COLOR=2 node app.js > log.txt     # force 256 colors
FORCE_COLOR=3 node app.js > log.txt     # force truecolor
FORCE_COLOR=true node app.js > log.txt  # auto-detect, fallback to 16 colors

node app.js --no-color                  # disable via flag
node app.js --color > log.txt           # auto-detect via flag, fallback to 16 colors

↑ top

Edge cases

Break style at New Line

Ansis and Chalk add a style break at each new line to correctly display multi-line text.
However, Picocolors doesn't handle this case.

ansis.bgRed('\n ERROR \n') + ansis.cyan('The file not found!') // βœ…
chalk.bgRed('\n ERROR \n') + chalk.cyan('The file not found!') // βœ…
pico.bgRed('\n ERROR \n') + pico.cyan('The file not found!')   // ❌

Break style at New Line

Nested template strings

Only Ansis handles this very useful use case.

ansis.red`R ${ansis.green`G ${ansis.blue`B`} G`} R` // βœ…
chalk.red`R ${chalk.green`G ${chalk.blue`B`} G`} R` // ❌
pico.red`R ${pico.green`G ${pico.blue`B`} G`} R`    // ❌

Nested template strings

Handling arguments

Compare how different libraries handle various input arguments in their functions.

ansis.red()          // βœ… ''
chalk.red()          // βœ… ''
pico.red()           // ❌ \e[31mundefined\e[39m

ansis.red(undefined) // βœ… ''
chalk.red(undefined) // ❌ \e[31mundefined\e[39m
pico.red(undefined)  // ❌ \e[31mundefined\e[39m

ansis.red(null)      // βœ… ''
chalk.red(null)      // ❌ \e[31mnull\e[39m
pico.red(null)       // ❌ \e[31mnull\e[39m

ansis.red('')        // βœ… ''
chalk.red('')        // βœ… ''
pico.red('')         // ❌ \e[31m\e[39m

ansis.reset()        // βœ… \e[0m
chalk.reset()        // ❌ ''
pico.reset()         // ❌ \e[0mundefined\e[0m
Libraryc.reset()c.red()c.red(undefined)c.red(null)c.red('')
ansisβœ…\e[0mβœ…''βœ…''βœ…''βœ…''
chalk❌''βœ…''❌'undefined'❌'null'βœ…''
picocolors❌undefined❌'undefined'❌'undefined'❌'null'❌'ESC'
tinyrainbow❌undefined❌'undefined'❌'undefined'❌'null'❌'ESC'
colorette❌''βœ…''βœ…''❌'null'βœ…''
kleur❌[object]❌[object]❌[object]❌'null'❌'ESC'
ansi-colors❌''βœ…''βœ…''βœ…''βœ…''
kolorist❌undefined❌'undefined'❌'undefined'❌'null'❌'ESC'
colors.js❌''βœ…''❌'undefined'❌'null'βœ…''
cli-color❌-❌'ESC'❌'ESC'❌'ESC'❌'ESC'
colors-cli❌-❌ Error❌'undefined'❌'null'❌'ESC'

Legend:

  • βœ…'' - Returns an empty string without ANSI escape codes. This is the correct and expected behavior.
  • βœ…\e[0m - Returns the reset escape code.
  • ❌'ESC' - Returns an empty string containing ANSI escape codes, e.g., \e[31m\e[39m.
  • ❌'undefined' - Returns the styled string undefined.
  • ❌'null' - Returns the styled string null.
  • ❌[object] - Returns an object of the library instance.
  • ❌- - The feature is not supported.
  • ❌Error - Causes a fatal error.

Other arguments are correctly handled by all libraries:

c.red(0)       // '0' in red
c.red(false)   // 'false' in red
c.red(true)    // 'true' in red
c.red(5/'1px') // 'NaN' in red
c.red(1/0)     // 'Infinity' in red

↑ top

Ansis vs styleText()

Since Node v22, the built-in util.styleText() has been officially introduced, supporting standard modifiers - the basic 16 colors and styles.

Where it works

Ansis

βœ… Node v10+
βœ… Chromium-based browsers and Safari
⚠️ Firefox DevTools don't render ANSI escape sequences

styleText

βœ… Node v22+ (native)
❌ No browser support (Node only)

Performance

In practical benchmarks, styleText() is 100x slower than Ansis:

ansis.red('text');        // 59.646.465 ops/sec
styleText('red', 'text'); //    579.832 ops/sec

See full benchmarks.

Color support detection

Ansis

  • Auto-detects terminal, TTY, CI and browser color support with automatic fallback
  • Supports NO_COLOR FORCE_COLOR COLORTERM --no-color --color
  • ansis.level returns the detected color level

styleText

  • Auto-detects terminal color support
  • Supports only NO_COLOR FORCE_COLOR NODE_DISABLE_COLORS

Simple styling

import { green } from 'ansis';
import { styleText } from 'node:util';

green`Success!`; // ansis
styleText('green', 'Success!');

green.bold`Success!`; // ansis
styleText(['green', 'bold'], 'Success!');

Nested styling

import { red, cyan } from 'ansis';
import { styleText } from 'node:util';

red`Error: ${cyan.bold`file.js`} not found!`; // ansis
styleText('red', `Error: ${styleText(['cyan', 'bold'], 'file.js')} not found!`);

Truecolor

Ansis: hex() rgb()

styleText: Limited to 16 ANSI colors.


↑ top

Compatibility

Check the minimum version of your tool required for compatibility with the latest Ansis.

ToolVersionCompatibilitySupports
Node.jsv14+βœ… Full supportCJS, ESM
Denov2.0+βœ… Full supportCJS, ESM
TypeScript/tscv5.0+βœ… Full supportCJS, ESM
esbuildv0.8+βœ… Full supportCJS, ESM
swcv1.2+βœ… Full supportCJS, ESM, FAUX
tsupv4.0+βœ… Full supportCJS, ESM, FAUX
tsxv3.0+βœ… Full supportCJS, ESM
Rollupv2.0+βœ… Full supportCJS, ESM
Rolldownv1.0.0-beta.8+βœ… Full supportCJS, ESM
Vitev2.5+βœ… Full supportESM
Turbov1.0+βœ… Full supportCJS, ESM
Webpackv5.0+βœ… Full supportCJS, ESM

Supports:

  • CJS: CommonJS module support.
  • ESM: ECMAScript module support.
  • FAUX: Fake or non-standard approach to module resolution (seen in swc).

Browser Compatibility for ANSI Codes

BrowserVersionColors Supported
Chromev20+TrueColor (16M)
Safariv10+TrueColor (16M)
Edgev12+TrueColor (16M)
Operav12+TrueColor (16M)
Bravev1.0+TrueColor (16M)
Vivaldiv1.0+TrueColor (16M)

Warning

Firefox doesn't natively support ANSI codes in the developer console.


⭐️ Star History

If you find this useful, please ⭐️ the repo.

Star History Chart


↑ top

License

ISC