Skip to content

1.3 ANSI Escape Codes

ANSI escape codes are the universal language of terminal control. Every TUI library — from ncurses to Bubble Tea to Ink — ultimately emits these. Understanding them means you can debug anything, and build anything without being blocked by a library.

Every escape sequence starts with the ESC character:

NotationHexDecimalMeaning
ESC\x1b27Escape character
\033samesameOctal notation (older Unix)
\esamesameBash shorthand

In TypeScript, use \x1b.

The most common form is the CSI (Control Sequence Introducer):

ESC [ <params> <command>
\x1b[ ... ...

For example, \x1b[2J means: ESC + [ + 2 + J = “erase entire screen”.

// Move cursor to row R, column C (1-indexed)
`\x1b[${row};${col}H`
// Move up N lines
`\x1b[${n}A`
// Move down N lines
`\x1b[${n}B`
// Move right N columns
`\x1b[${n}C`
// Move left N columns
`\x1b[${n}D`
// Move to beginning of line N lines down
`\x1b[${n}E`
// Move to beginning of line N lines up
`\x1b[${n}F`
// Move to column N on current line
`\x1b[${n}G`
// Save cursor position
`\x1b[s` // or \x1b7
// Restore cursor position
`\x1b[u` // or \x1b8
// Clear from cursor to end of screen
`\x1b[0J` // or \x1b[J
// Clear from cursor to beginning of screen
`\x1b[1J`
// Clear entire screen (cursor stays where it is)
`\x1b[2J`
// Clear entire screen AND scrollback buffer
`\x1b[3J`
// Clear from cursor to end of line
`\x1b[0K` // or \x1b[K
// Clear from cursor to beginning of line
`\x1b[1K`
// Clear entire current line
`\x1b[2K`

SGR: Select Graphic Rendition (Colors & Styles)

Section titled “SGR: Select Graphic Rendition (Colors & Styles)”

The m command sets text attributes. Multiple attributes can be combined with ;:

`\x1b[${...attrs...}m`
`\x1b[0m` // reset all attributes

Always reset after setting colors/styles, or every subsequent character will inherit them.

`\x1b[1m` // bold
`\x1b[2m` // dim
`\x1b[3m` // italic
`\x1b[4m` // underline
`\x1b[5m` // blink
`\x1b[7m` // reverse (swap fg/bg colors)
`\x1b[8m` // hidden (invisible)
`\x1b[9m` // strikethrough

These are the original 8 colors + bright variants. The exact shade depends on your terminal’s color scheme:

CodeForegroundCodeBackground
30Black40Black
31Red41Red
32Green42Green
33Yellow43Yellow
34Blue44Blue
35Magenta45Magenta
36Cyan46Cyan
37White47White
90–97Bright variants100–107Bright variants
// Green text on black background
`\x1b[32;40m Hello \x1b[0m`
// Bold bright yellow
`\x1b[1;93m Warning \x1b[0m`
// Foreground: \x1b[38;5;<n>m where n = 0–255
`\x1b[38;5;214m` // orange foreground
// Background: \x1b[48;5;<n>m
`\x1b[48;5;17m` // dark blue background

The 256-color palette:

  • 0–7: standard colors (same as 4-bit 30–37)
  • 8–15: high-intensity colors (same as 4-bit 90–97)
  • 16–231: 6×6×6 color cube
  • 232–255: grayscale ramp

Modern terminals support full RGB:

// Foreground: \x1b[38;2;<r>;<g>;<b>m
`\x1b[38;2;255;128;0m` // RGB orange foreground
// Background: \x1b[48;2;<r>;<g>;<b>m
`\x1b[48;2;30;30;46m` // dark background

True color is supported in: Kitty, Alacritty, WezTerm, Windows Terminal, iTerm2, modern GNOME Terminal.

`\x1b[?25l` // hide cursor
`\x1b[?25h` // show cursor

TUIs typically hide the cursor during rendering and only show it when expecting text input, to avoid a flickering cursor jumping around the screen.

Most TUI programs switch to an alternate screen buffer on start and restore the normal screen on exit. This means the user’s shell history is preserved — when they quit your app, the terminal looks exactly as it did before:

`\x1b[?1049h` // enter alternate screen
`\x1b[?1049l` // exit alternate screen

Always exit the alternate screen when your program exits, including on Ctrl+C. We will cover this with cleanup handlers in Module 2.

You can receive mouse click and scroll events:

`\x1b[?1000h` // enable mouse click tracking
`\x1b[?1000l` // disable mouse click tracking
`\x1b[?1002h` // enable mouse click + drag tracking
`\x1b[?1003h` // enable all mouse events (including movement)
`\x1b[?1006h` // SGR mouse encoding (handles large terminals, use this)

Mouse events arrive as escape sequences on stdin. We will parse them in Module 2.

Memorizing all these codes is not necessary. The ansi-escapes package provides them as named exports:

import ansiEscapes from 'ansi-escapes';
process.stdout.write(ansiEscapes.cursorTo(5, 3)); // move cursor
process.stdout.write(ansiEscapes.eraseScreen); // clear screen
process.stdout.write(ansiEscapes.cursorHide); // hide cursor
process.stdout.write(ansiEscapes.enterAlternativeScreen);

We use it throughout this course. But now that you know what’s underneath, you could always replace it with the raw codes if you needed to.

Open a terminal and run:

Terminal window
printf '\x1b[2J\x1b[H' # clear screen, move to top-left
printf '\x1b[5;10H\x1b[32mHello\x1b[0m' # move to row 5 col 10, green "Hello"
printf '\x1b[?25l' # hide cursor
printf '\x1b[?25h' # show cursor again

In the next lesson we put these to work with chalk and write real styled output.