Skip to main content
ansicode
JavaScript / Node.js

ANSI escape codes in JavaScript / Node.js

Node's `process.stdout.write` and `console.log` are both byte-clean. The browser console (DevTools) accepts a CSS-styled subset of escapes via `%c`, NOT ANSI bytes — those only render in real terminals. For ergonomics, `chalk` is the canonical choice; `picocolors` is the same idea in ~100x less code.

Recommended libraries

  • chalk

    Chainable colour API: `chalk.bold.red('oops')`. Auto-detects support level (16 / 256 / 16M colours), honours `NO_COLOR` and `FORCE_COLOR`.

  • picocolors

    Drop-in chalk-shaped API in ~100 LOC and zero dependencies. Used by Vite, Vue, Tailwind for cold-start time.

  • ansi-escapes

    Constants and helpers for non-SGR escapes: cursor moves, clear lines, alt screen, OSC 8 hyperlinks, OSC 52 clipboard, iTerm2 imgcat.

  • ink

    React for the terminal — components render to ANSI. Used by Gatsby, Yarn, Shopify CLI. Pairs with `ink-ui` for batteries-included widgets.

Idiomatic patterns

Direct write (no dependency)
process.stdout.write('\x1b[1;31merror:\x1b[0m permission denied\n');
Chalk for readable styling
import chalk from 'chalk';

console.log(chalk.bold.red('error:'), 'permission denied');
console.log(chalk.rgb(203, 166, 247)('lavender truecolor'));
OSC 8 clickable link (Node 14+)
function link(text, url) {
  const ESC = '\x1b';
  return `${ESC}]8;;${url}${ESC}\\${text}${ESC}]8;;${ESC}\\`;
}

console.log('see ' + link('the docs', 'https://ansicode.eversources.app'));
In-place spinner (CR + cursor hide)
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
let i = 0;
process.stdout.write('\x1b[?25l');                       // hide cursor
const id = setInterval(() => {
  process.stdout.write('\r' + frames[i = (i + 1) % frames.length] + ' loading');
}, 80);

process.on('exit', () => {
  clearInterval(id);
  process.stdout.write('\r\x1b[K\x1b[?25h');           // restore line + cursor
});

Related sequences

Other languages