CJS/ESM ANSI color library for terminals, CI and Chromium-based browser consoles. Compatible with Bun, Deno, Next.JS.
508
stars
209
commits
JavaScript
primary language
Sep 6, 2026
updated

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`);
styleText() 🔄 Migrating from ⚖️ Alternatives ✅ Compare features🎨 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)
Ansis is the fastest when using 2 or more styles, which is the common real-world use case.
| Library | 1 style | 2+ styles |
|---|---|---|
ansis | 60M ops/sec | 🏆 60M ops/sec |
picocolors | 🏆 109M ops/sec | 58M ops/sec |
chalk | 55M ops/sec | 47M ops/sec |
util.styleText | 0.5M ops/sec | 0.5M ops/sec |
🎨 Colors & Styles
dim bold italic underline strikethroughred redBright bgRed bgRedBright ...fg(n) bg(n)hex('#FF75D1') rgb(224, 17, 95) bgHex() bgRgb()orange() bgPink() ... - via extend()✍️ Syntax
red.bold.underline - no nested calls like red(bold(underline()))red`text` - no parenthesesred`Error: ${cyan`file.js`} not found` - no string concatenations🛠️ Utilities
ansis.strip(red('text')) → plain 'text'blue.link('https://...', 'Click here'), link('https://...')open / close - `${red.open}Error${red.close} file not found`💻 Environment
NO_COLOR FORCE_COLOR COLORTERM--no-color --color⚙️ Compatibility
chalk ansi-colors colorette and others🎯 You might also like
ansilight- Truecolor syntax highlighter for the terminal with 256highlight.jsthemesflaget- CLI argument parsing. A smaller (5 kB) and faster alternative toyargs-parser(85 kB)
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
npm install ansis
For Node.js 10–12+ use special build
npm install ansis@node10
ESM
import ansis, { red, bold, fg, hex, rgb } from 'ansis';
CJS
const ansis = require('ansis');
const { red, bold, fg, hex, rgb } = require('ansis');
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`;
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
dim bold italic underline strikethroughinverse visible hidden reset
There are 16 basic colors: 8 standard and 8 bright variants.
| Example | Color | Background | Bright Example | Bright Color | Bright Background |
|---|---|---|---|---|---|
![]() | black | bgBlack | ![]() | gray | bgGray |
![]() | red | bgRed | ![]() | redBright | bgRedBright |
![]() | green | bgGreen | ![]() | greenBright | bgGreenBright |
![]() | yellow | bgYellow | ![]() | yellowBright | bgYellowBright |
![]() | blue | bgBlue | ![]() | blueBright | bgBlueBright |
![]() | magenta | bgMagenta | ![]() | magentaBright | bgMagentaBright |
![]() | cyan | bgCyan | ![]() | cyanBright | bgCyanBright |
![]() | white | bgWhite | ![]() | whiteBright | bgWhiteBright |
fg(code) - chalk.ansi256(code) equivalentbg(code) - chalk.bgAnsi256(code) equivalentimport { 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`;
See ANSI color codes.
If a terminal supports only 16 colors then ANSI 256 colors will be interpolated into base 16 colors.
hex() rgb()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.
Ansis automatically interpolates to the best available color level.
Truecolor → 256 colors → 16 colors → no colors (b&w)

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
Ansisinstance and callextend()on it.
[!TIP] For all CSS named colors use css-color-names package.

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 textlink(url) - URL as both target and textimport { 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.
Ansis automatically detects the supported color level:
0 – No color1 – 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
--save-to-logimport { 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'))
Ansis detects color support from the runtime environment in this order:
Chromium browser-like runtimes
COLORTERM (some terminals set it even when output is not TTY)
truecolor or 24bit -> truecoloransi256 -> 256 colorsansi -> 16 colorsCI environment (not TTY)
Terminal
TERM=dumb -> no colorsPM2 and Next.js non-TTY runtimes -> color outputWindows
256-color terminals
Fallback
| Terminal | ANSI 16 colors | ANSI 256 colors | True Color | env. TERM | env. COLORTERM | Specifically ENV variables |
|---|---|---|---|---|---|---|
| Azure CI | ✅ | ❌ | ❌ | dumb | TF_BUILD AGENT_NAME | |
| GitHub CI | ✅ | ✅ | ✅ | dumb | CI, GITHUB_ACTIONS | |
| GitTea CI | ✅ | ✅ | ✅ | dumb | CI, GITEA_ACTIONS | |
| GitLab CI | ✅ | ❌ | ❌ | dumb | CI, GITLAB_CI | |
| Travis CI | ✅ | ❌ | ❌ | dumb | TRAVIS | |
| PM2 not isTTY | ✅[^1] | ✅[^1] | ✅[^1] | dumb | PM2_HOME pm_id | |
| JetBrains TeamCity >=2020.1.1 | ✅ | ✅ | ❌ | TEAMCITY_VERSION | ||
| JetBrains IDEA | ✅ | ✅ | ✅ | xterm-256color | TERMINAL_EMULATOR='JetBrains-JediTerm' | |
| VS Code | ✅ | ✅ | ✅ | xterm-256color | truecolor | |
| Windows Terminal | ✅ | ✅ | ✅[^2] | |||
| Windows PowerShell | ✅ | ✅ | ✅[^2] | |||
| macOS Terminal | ✅ | ✅ | ❌ | xterm-256color | ||
| iTerm | ✅ | ✅ | ✅ | xterm-256color | truecolor | |
| Kitty | ✅ | ✅ | ✅ | xterm-kitty | truecolor | |
| KDE Konsole | ✅ | ✅ | ✅ | xterm-256color | truecolor |
See also:
Ansis detects color support automatically, but you can override it with environment variables and CLI flags.
[!NOTE]
Priority order, from lowest to highest:
- auto-detection
NO_COLOR- CLI color flags
FORCE_COLOR
NO_COLORSet to any non-empty value (1, true) to disable color output (see no-color.org):
NO_COLOR=1 node app.js
FORCE_COLORForce or override color support via environment variable (see force-color.org).
| Value | Behavior |
|---|---|
0 or false | Disable colors (level 0) |
1 | Force 16 colors (level 1) |
2 | Force 256 colors (level 2) |
3 | Force truecolor (level 3) |
true or any other string | Auto-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=0disables 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=trueand an empty value enable colors.
This matches Node.js, but the original force-color.org rule ignores an empty string.
COLORTERMHint the auto-detected color level using terminal emulator conventions:
| Value | Level |
|---|---|
ansi | 16 colors (level 1) |
ansi256 | 256 colors (level 2) |
truecolor or 24bit | Truecolor (level 3) |
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
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
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!') // ❌

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` // ❌

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
| Library | c.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' |
'' - 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
styleText()Since Node v22, the built-in util.styleText()
has been officially introduced, supporting standard modifiers - the basic 16 colors and styles.
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)
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.
Ansis
NO_COLOR FORCE_COLOR COLORTERM --no-color --coloransis.level returns the detected color levelstyleText
NO_COLOR FORCE_COLOR NODE_DISABLE_COLORSimport { green } from 'ansis';
import { styleText } from 'node:util';
green`Success!`; // ansis
styleText('green', 'Success!');
green.bold`Success!`; // ansis
styleText(['green', 'bold'], 'Success!');
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!`);
Ansis: hex() rgb()
styleText: Limited to 16 ANSI colors.
Check the minimum version of your tool required for compatibility with the latest Ansis.
| Tool | Version | Compatibility | Supports |
|---|---|---|---|
| Node.js | v14+ | ✅ Full support | CJS, ESM |
| Deno | v2.0+ | ✅ Full support | CJS, ESM |
| TypeScript/tsc | v5.0+ | ✅ Full support | CJS, ESM |
| esbuild | v0.8+ | ✅ Full support | CJS, ESM |
| swc | v1.2+ | ✅ Full support | CJS, ESM, FAUX |
| tsup | v4.0+ | ✅ Full support | CJS, ESM, FAUX |
| tsx | v3.0+ | ✅ Full support | CJS, ESM |
| Rollup | v2.0+ | ✅ Full support | CJS, ESM |
| Rolldown | v1.0.0-beta.8+ | ✅ Full support | CJS, ESM |
| Vite | v2.5+ | ✅ Full support | ESM |
| Turbo | v1.0+ | ✅ Full support | CJS, ESM |
| Webpack | v5.0+ | ✅ Full support | CJS, ESM |
Supports:
| Browser | Version | Colors Supported |
|---|---|---|
| Chrome | v20+ | TrueColor (16M) |
| Safari | v10+ | TrueColor (16M) |
| Edge | v12+ | TrueColor (16M) |
| Opera | v12+ | TrueColor (16M) |
| Brave | v1.0+ | TrueColor (16M) |
| Vivaldi | v1.0+ | TrueColor (16M) |
[!WARNING] Firefox doesn't natively support ANSI codes in the developer console.
If you find this useful, please ⭐️ the repo.
JavaScript
89.9%
TypeScript
9.9%
CJS/ESM ANSI color library for terminals, CI and Chromium-based browser consoles. Compatible with Bun, Deno, Next.JS.
508
stars
209
commits
JavaScript
primary language
Sep 6, 2026
updated

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`);
styleText() 🔄 Migrating from ⚖️ Alternatives ✅ Compare features🎨 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)
Ansis is the fastest when using 2 or more styles, which is the common real-world use case.
| Library | 1 style | 2+ styles |
|---|---|---|
ansis | 60M ops/sec | 🏆 60M ops/sec |
picocolors | 🏆 109M ops/sec | 58M ops/sec |
chalk | 55M ops/sec | 47M ops/sec |
util.styleText | 0.5M ops/sec | 0.5M ops/sec |
🎨 Colors & Styles
dim bold italic underline strikethroughred redBright bgRed bgRedBright ...fg(n) bg(n)hex('#FF75D1') rgb(224, 17, 95) bgHex() bgRgb()orange() bgPink() ... - via extend()✍️ Syntax
red.bold.underline - no nested calls like red(bold(underline()))red`text` - no parenthesesred`Error: ${cyan`file.js`} not found` - no string concatenations🛠️ Utilities
ansis.strip(red('text')) → plain 'text'blue.link('https://...', 'Click here'), link('https://...')open / close - `${red.open}Error${red.close} file not found`💻 Environment
NO_COLOR FORCE_COLOR COLORTERM--no-color --color⚙️ Compatibility
chalk ansi-colors colorette and others🎯 You might also like
ansilight- Truecolor syntax highlighter for the terminal with 256highlight.jsthemesflaget- CLI argument parsing. A smaller (5 kB) and faster alternative toyargs-parser(85 kB)
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
npm install ansis
For Node.js 10–12+ use special build
npm install ansis@node10
ESM
import ansis, { red, bold, fg, hex, rgb } from 'ansis';
CJS
const ansis = require('ansis');
const { red, bold, fg, hex, rgb } = require('ansis');
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`;
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
dim bold italic underline strikethroughinverse visible hidden reset
There are 16 basic colors: 8 standard and 8 bright variants.
| Example | Color | Background | Bright Example | Bright Color | Bright Background |
|---|---|---|---|---|---|
![]() | black | bgBlack | ![]() | gray | bgGray |
![]() | red | bgRed | ![]() | redBright | bgRedBright |
![]() | green | bgGreen | ![]() | greenBright | bgGreenBright |
![]() | yellow | bgYellow | ![]() | yellowBright | bgYellowBright |
![]() | blue | bgBlue | ![]() | blueBright | bgBlueBright |
![]() | magenta | bgMagenta | ![]() | magentaBright | bgMagentaBright |
![]() | cyan | bgCyan | ![]() | cyanBright | bgCyanBright |
![]() | white | bgWhite | ![]() | whiteBright | bgWhiteBright |
fg(code) - chalk.ansi256(code) equivalentbg(code) - chalk.bgAnsi256(code) equivalentimport { 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`;
See ANSI color codes.
If a terminal supports only 16 colors then ANSI 256 colors will be interpolated into base 16 colors.
hex() rgb()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.
Ansis automatically interpolates to the best available color level.
Truecolor → 256 colors → 16 colors → no colors (b&w)

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
Ansisinstance and callextend()on it.
[!TIP] For all CSS named colors use css-color-names package.

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 textlink(url) - URL as both target and textimport { 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.
Ansis automatically detects the supported color level:
0 – No color1 – 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
--save-to-logimport { 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'))
Ansis detects color support from the runtime environment in this order:
Chromium browser-like runtimes
COLORTERM (some terminals set it even when output is not TTY)
truecolor or 24bit -> truecoloransi256 -> 256 colorsansi -> 16 colorsCI environment (not TTY)
Terminal
TERM=dumb -> no colorsPM2 and Next.js non-TTY runtimes -> color outputWindows
256-color terminals
Fallback
| Terminal | ANSI 16 colors | ANSI 256 colors | True Color | env. TERM | env. COLORTERM | Specifically ENV variables |
|---|---|---|---|---|---|---|
| Azure CI | ✅ | ❌ | ❌ | dumb | TF_BUILD AGENT_NAME | |
| GitHub CI | ✅ | ✅ | ✅ | dumb | CI, GITHUB_ACTIONS | |
| GitTea CI | ✅ | ✅ | ✅ | dumb | CI, GITEA_ACTIONS | |
| GitLab CI | ✅ | ❌ | ❌ | dumb | CI, GITLAB_CI | |
| Travis CI | ✅ | ❌ | ❌ | dumb | TRAVIS | |
| PM2 not isTTY | ✅[^1] | ✅[^1] | ✅[^1] | dumb | PM2_HOME pm_id | |
| JetBrains TeamCity >=2020.1.1 | ✅ | ✅ | ❌ | TEAMCITY_VERSION | ||
| JetBrains IDEA | ✅ | ✅ | ✅ | xterm-256color | TERMINAL_EMULATOR='JetBrains-JediTerm' | |
| VS Code | ✅ | ✅ | ✅ | xterm-256color | truecolor | |
| Windows Terminal | ✅ | ✅ | ✅[^2] | |||
| Windows PowerShell | ✅ | ✅ | ✅[^2] | |||
| macOS Terminal | ✅ | ✅ | ❌ | xterm-256color | ||
| iTerm | ✅ | ✅ | ✅ | xterm-256color | truecolor | |
| Kitty | ✅ | ✅ | ✅ | xterm-kitty | truecolor | |
| KDE Konsole | ✅ | ✅ | ✅ | xterm-256color | truecolor |
See also:
Ansis detects color support automatically, but you can override it with environment variables and CLI flags.
[!NOTE]
Priority order, from lowest to highest:
- auto-detection
NO_COLOR- CLI color flags
FORCE_COLOR
NO_COLORSet to any non-empty value (1, true) to disable color output (see no-color.org):
NO_COLOR=1 node app.js
FORCE_COLORForce or override color support via environment variable (see force-color.org).
| Value | Behavior |
|---|---|
0 or false | Disable colors (level 0) |
1 | Force 16 colors (level 1) |
2 | Force 256 colors (level 2) |
3 | Force truecolor (level 3) |
true or any other string | Auto-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=0disables 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=trueand an empty value enable colors.
This matches Node.js, but the original force-color.org rule ignores an empty string.
COLORTERMHint the auto-detected color level using terminal emulator conventions:
| Value | Level |
|---|---|
ansi | 16 colors (level 1) |
ansi256 | 256 colors (level 2) |
truecolor or 24bit | Truecolor (level 3) |
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
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
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!') // ❌

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` // ❌

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
| Library | c.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' |
'' - 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
styleText()Since Node v22, the built-in util.styleText()
has been officially introduced, supporting standard modifiers - the basic 16 colors and styles.
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)
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.
Ansis
NO_COLOR FORCE_COLOR COLORTERM --no-color --coloransis.level returns the detected color levelstyleText
NO_COLOR FORCE_COLOR NODE_DISABLE_COLORSimport { green } from 'ansis';
import { styleText } from 'node:util';
green`Success!`; // ansis
styleText('green', 'Success!');
green.bold`Success!`; // ansis
styleText(['green', 'bold'], 'Success!');
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!`);
Ansis: hex() rgb()
styleText: Limited to 16 ANSI colors.
Check the minimum version of your tool required for compatibility with the latest Ansis.
| Tool | Version | Compatibility | Supports |
|---|---|---|---|
| Node.js | v14+ | ✅ Full support | CJS, ESM |
| Deno | v2.0+ | ✅ Full support | CJS, ESM |
| TypeScript/tsc | v5.0+ | ✅ Full support | CJS, ESM |
| esbuild | v0.8+ | ✅ Full support | CJS, ESM |
| swc | v1.2+ | ✅ Full support | CJS, ESM, FAUX |
| tsup | v4.0+ | ✅ Full support | CJS, ESM, FAUX |
| tsx | v3.0+ | ✅ Full support | CJS, ESM |
| Rollup | v2.0+ | ✅ Full support | CJS, ESM |
| Rolldown | v1.0.0-beta.8+ | ✅ Full support | CJS, ESM |
| Vite | v2.5+ | ✅ Full support | ESM |
| Turbo | v1.0+ | ✅ Full support | CJS, ESM |
| Webpack | v5.0+ | ✅ Full support | CJS, ESM |
Supports:
| Browser | Version | Colors Supported |
|---|---|---|
| Chrome | v20+ | TrueColor (16M) |
| Safari | v10+ | TrueColor (16M) |
| Edge | v12+ | TrueColor (16M) |
| Opera | v12+ | TrueColor (16M) |
| Brave | v1.0+ | TrueColor (16M) |
| Vivaldi | v1.0+ | TrueColor (16M) |
[!WARNING] Firefox doesn't natively support ANSI codes in the developer console.
If you find this useful, please ⭐️ the repo.
JavaScript
89.9%
TypeScript
9.9%