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 —
Stringextensions like'error'.red().bold(). Smaller surface area than chalkdart; pairs well with code that already uses the extension-method idiom. Auto-respectsNO_COLOR. - cli_util
Google's first-party Dart CLI helpers — used by
dartandfluttertooling. Includes anansimodule with capability-awaregreen,red, etc., plusAnsi(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 withstdout.supportsAnsiEscapes.
Idiomatic patterns
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');
}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');
}
}// 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'));
}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.