Skip to main content
ansicode
Dart

ANSI escape codes in Dart — stdout.supportsAnsiEscapes, chalkdart, tint

Dart's `dart:io` `stdout` already exposes the canonical capability check most other ecosystems force you to roll yourself — `stdout.supportsAnsiEscapes` returns `true` on a TTY that understands VT sequences, `false` when piped, redirected, or running on a legacy Conhost without VT enabled. Pair it with raw `stdout.write('\x1B[31m…\x1B[0m')` (Dart accepts both `\x1B` and `\u001B`) and you have a portable starting point with zero dependencies on macOS, Linux, and Windows Terminal / Conhost 1709+. For ergonomic colour APIs reach for `chalkdart` (the most popular Dart ANSI library — chained-extension API mirrored after Node's `chalk`), `tint` (compact, modern), or `cli_util` (Google's first-party CLI helpers including an ANSI module). The Flutter SDK's own `flutter` CLI uses these primitives — its progress / build-status output is a canonical reference for Dart-shaped capability gating.

Recommended libraries

  • chalkdart

    Most-popular Dart ANSI library — chained-extension API mirroring Node's `chalk`: `print(chalk.red.bold('error'))`. Supports TrueColor (`chalk.rgb(255,128,0)`), 256-colour, named colours, background pairs, and underline variants. Pure Dart, zero native deps.

  • tint

    Compact modern alternative — `String` extensions like `'error'.red().bold()`. Smaller surface area than chalkdart; pairs well with code that already uses the extension-method idiom. Auto-respects `NO_COLOR`.

  • cli_util

    Google's first-party Dart CLI helpers — used by `dart` and `flutter` tooling. Includes an `ansi` module with capability-aware `green`, `red`, etc., plus `Ansi(supportsAnsi)` constructor for explicit gating. The canonical Dart pattern for production CLIs.

  • ansi_styles

    Low-level escape-sequence map — `AnsiStyles.red('text')`, `AnsiStyles.bgBlue('text')`, plus exposed escape strings for use cases that need the raw bytes (e.g. templating into a custom render). No capability detection — pair with `stdout.supportsAnsiEscapes`.

Idiomatic patterns

Direct stdout.write with \x1B
import 'dart:io';

void main() {
  // Dart accepts both \x1B (hex) and \u001B (Unicode) — pick one.
  stdout.write('\x1B[1;31merror:\x1B[0m permission denied\n');
  stdout.write('\x1B[33mwarn:\x1B[0m deprecated flag\n');
  stdout.write('\x1B[32mok:\x1B[0m 142 tests passed\n');

  // Truecolor (38;2;R;G;B):
  stdout.write('\x1B[38;2;255;128;0morange truecolor\x1B[0m\n');
}
Stdlib capability check — stdout.supportsAnsiEscapes
import 'dart:io';

// dart:io's stdout already exposes the portable capability check.
// supportsAnsiEscapes returns false on a piped stdout, on a non-TTY,
// and on legacy Windows console without VT enabled.

String style(String text, String sgr) {
  if (!stdout.supportsAnsiEscapes) return text;
  return '\x1B[${sgr}m${text}\x1B[0m';
}

void main() {
  print(style('OK', '32'));
  print(style('FAIL', '1;31'));

  // Bonus — also reflects redirection state independently:
  if (stdout.hasTerminal) {
    final cols = stdout.terminalColumns;  // dynamic width for bars / tables
    print('terminal width: $cols');
  }
}
chalkdart — chained extension API
// pubspec.yaml:
//   dependencies:
//     chalkdart: ^3.0.0
import 'package:chalkdart/chalk.dart';

void main() {
  print(chalk.red.bold('error:') + ' permission denied');
  print(chalk.yellow('warn:') + ' deprecated flag');
  print(chalk.green('ok:') + ' 142 tests passed');

  // Background + foreground composition:
  print(chalk.white.bold.bgRed(' FATAL '));

  // Truecolor via rgb / hex:
  print(chalk.rgb(255, 128, 0)('orange truecolor'));
  print(chalk.hex('#ff8000')('same, hex form'));
}
NO_COLOR + Platform.environment + Flutter caveats
import 'dart:io';

bool ansiCapable() {
  // Honour the Unix-standard kill switch first.
  if (Platform.environment['NO_COLOR'] != null) return false;
  // dart:io's own portable TTY check.
  if (!stdout.supportsAnsiEscapes) return false;
  return true;
}

void main() {
  if (ansiCapable()) {
    stdout.write('\x1B[32mready\x1B[0m\n');
  } else {
    stdout.write('ready\n');
  }
}

// Flutter caveats:
// 1) print() in a Flutter app routes to platform logs (logcat / NSLog),
//    which do NOT parse ANSI — your bytes appear verbatim. Gate output
//    with kReleaseMode / kDebugMode or use the developer.log API.
// 2) flutter run --machine emits JSON, never ANSI — supportsAnsiEscapes
//    returns false in that mode.
// 3) On Windows, supportsAnsiEscapes already accounts for VT-enabled
//    Conhost (1709+) and Windows Terminal — no SetConsoleMode needed.

Related sequences

Other languages