CSI escape codes — cursor, erase, scroll, position
Control Sequence Introducer. The ESC [ family minus its SGR sub-set — cursor movement (up / down / forward / back / column / absolute position), erase (line / display), scroll, save / restore, and the handful of CSI sequences for window and cursor reporting.
60 sequences
When to use CSI
Reach for CSI when you need to move the cursor or change the screen contents — anything positional or structural, not stylistic. CSI sequences open with \x1b[ and finish on a non-m letter: H move to position, J erase display, K erase line, n query state, S / T scroll, r set scroll margins, A / B / C / D step the cursor. Each operation fires the moment it's parsed — there's no persistent CSI mode (that's DEC's lane). Reach for SGR (final byte m) for colour, OSC for window chrome, DEC modes for switches like alt-screen — CSI is the workhorse for everything else.
Common CSI one-liners
Paste any of these into bash / zsh — printf interprets the \x1b byte.
Clear screen + cursor home printf '\x1b[2J\x1b[H'Erase to end of line printf '\x1b[K'Query cursor position (CPR) printf '\x1b[6n'
CSI cookbook — six purposes the family covers
CSI (Control Sequence Introducer) is the largest active corner of the escape-code dialect — over 60 finals doing everything except palette and chrome (those are SGR and OSC). Six stops, top to bottom: the envelope syntax itself, cursor movement, screen / line erase, the round-trip queries terminals answer on stdin, scroll-region and margin setup that TUIs use to carve out fixed regions, and local insert / delete / cursor-shape ops that avoid the cost of a full repaint.
1. The envelope —
\x1b[…<final-byte>Every CSI sequence is
\x1b[(ESC[), an optional private-marker (?for DEC private modes,</=/>for xterm-defined variants), zero or more numeric parameters separated by;, and a final byte in the\x40–\x7Erange that picks the action. Unlike OSC there's no terminator — the final byte ends the sequence. SGR usesm(\x1b[31m), ED usesJ, EL usesK, CUP (cursor position) usesH, DSR usesn, DA usesc— over 60 finals in active use across ECMA-48 + xterm. Parameters default to 1 or 0 depending on the action; omitted is equivalent to the default, so\x1b[A(move up 1) is identical to\x1b[1A. There's also an 8-bit CSI form\x9b …you'll see in old VT manuals but never in the wild.2. Cursor movement — CUU / CUD / CUF / CUB + CUP + CHA / VPA
The eight cursor primitives every TUI lives on. CUU / CUD / CUF / CUB (
\x1b[NA/B/C/D) move the cursor up / down / forward / backward byNcells (default 1) without crossing the screen edge. CUP (\x1b[r;cH, aliasf) jumps to absolute rowr, columnc(1-indexed). CHA (\x1b[NG) and VPA (\x1b[Nd) jump to absolute column / row keeping the other axis. CNL / CPL (\x1b[NE/F) move N lines down / up but also reset column to 1 — useful for paragraph-style cursor flow. SCOSC / SCORC (\x1b[s/\x1b[u) save / restore one cursor slot — older than DECSC\x1b7/ DECRC\x1b8but identical in effect on every modern emulator.See alsoCUU / CUD / CUF / CUB — Move cursorCUP — Set cursor positionCHA — Cursor horizontal absolute (column)VPA — Vertical line position absolute (CSI d)HVP — Horizontal and vertical position (CSI f, alias of CUP)SCOSC / SCORC — Save / Restore cursor (CSI s / u)CNL / CPL — Cursor next / previous line3. Erase — ED
Jand ELKTwo finals do all the erasing:
Jfor screen,Kfor line. Each takes a parameter selecting the range:0(default) from cursor to end,1from start to cursor,2the whole screen / line, and3forJalso wipes scrollback (xterm extension, supported by most modern emulators). The canonical "clear screen and home" combo every TUI emits on launch is\x1b[2J\x1b[H— erase whole screen, then move cursor to row 1 column 1. ECH\x1b[NX(covered in section 6) is the in-place alternative that overwrites N cells with blanks without moving anything else. For partial repaints,\x1b[K(erase to end of line) after a CUP jump is the cheapest way to wipe a row before redrawing it.4. Queries — DA, DA2, DSR, DECRQM
Round-trip queries where the terminal replies back on stdin — programs that emit a query must read the response or it leaks into the next user input. DA
\x1b[c(Primary Device Attributes) asks "what are you?" — modern emulators reply\x1b[?<id>;<feature>;<feature>cadvertising VT100 / VT200 / VT400 base + supported features (sixel, regis, colour, etc.). DA2\x1b[>creturns model + firmware version — useful for distinguishing iTerm2 from kitty from xterm. DSR\x1b[6n(cursor position) returns\x1b[r;cR;\x1b[5nreturns terminal-OK status. DECRQM\x1b[?<n>$preads whether DEC private modenis currently set / reset / permanent / unsupported (one of0/1/2/3/4in the reply). Use case: feature-detect alt-screen support before emitting\x1b[?1049h.5. Margins & scroll region — DECSTBM
rand DECSLRMsDECSTBM
\x1b[<top>;<bottom>rsets the scrolling region to rowstop–bottom(1-indexed, inclusive). Inside this region scroll-up / scroll-down (\x1b[NS/\x1b[NT) and IL / DL only affect those rows; the rest of the screen stays put. The classic use is a stationary status bar at the bottom — set\x1b[1;<screenrows-1>rand the status row never scrolls away. To reset to full-screen scrolling, emit\x1b[rwith no arguments. DECSLRM\x1b[<left>;<right>ssets horizontal margins the same way, but only takes effect when DECLRMM (\x1b[?69h) is enabled first — most TUIs skip horizontal margins entirely. Without DECLRMM,\x1b[sis interpreted as SCOSC (save cursor) — a classic mode-confusion trap when porting code between terminals.6. Insert / delete / cursor shape — IL / DL / ICH / DCH / ECH + DECSCUSR
Local edits that don't need a full repaint. IL
\x1b[NLinserts N blank lines at the cursor, pushing existing content down (off the scroll region). DL\x1b[NMdeletes N lines, pulling content up. ICH\x1b[N@and DCH\x1b[NPdo the same on the column axis within a single line. ECH\x1b[NXerases N cells in place — overwrites with blanks without shifting anything else, the right primitive for clearing a known-width field. DECSCUSR\x1b[N qpicks cursor shape:1blinking block (default),2steady block,3blinking underline,4steady underline,5blinking bar,6steady bar — vim'sterminal-modetoggles between2and6to show insert vs normal. Honoured by xterm, kitty, iTerm2, wezterm, alacritty, ghostty, Windows Terminal, gnome-terminal 3.16+, konsole; Linux console ignores.
All sequences in this family
- CUU / CUD / CUF / CUB — Move cursor
\x1b[NA (up; B down, C right, D left)Move the cursor up / down / right / left by N cells.
- CNL / CPL — Cursor next / previous line
\x1b[NE (down N lines, col 1) \x1b[NF (up)Move the cursor to column 1 of the line N below (CNL) or above (CPL).
- CHA — Cursor horizontal absolute (column)
\x1b[NGMove the cursor to column N of the current row (1-indexed).
- CUP — Set cursor position
\x1b[row;colHMove the cursor to absolute row/column (1-indexed).
- ED — Erase in display (\x1b[2J clear screen)
\x1b[NJErase part or all of the screen.
- EL — Erase in line (\x1b[K)
\x1b[NKErase part or all of the current line.
- SU / SD — Scroll up / down
\x1b[NS (scroll up) \x1b[NT (scroll down)Scroll the screen contents up (SU) or down (SD) by N lines without moving the cursor.
- DECSCUSR — Cursor shape
\x1b[N\x20q (N = 0..6)Change the cursor shape: block, underline, or bar (with optional blink).
- DECSTR — Soft terminal reset
\x1b[!pReset DEC private modes and SGR to defaults WITHOUT clearing the screen or scrollback.
- CBT — Cursor Backward Tabulation (CSI Z)
\x1b[NZMove the cursor back N tab stops — the reverse of pressing Tab.
- TBC — Tab Clear (CSI g)
\x1b[g (clear current) \x1b[3g (clear all)Clear one or all tab stops, changing where HT and CBT land.
- DECSTBM — Set Top/Bottom Margins (CSI r)
\x1b[T;BrDefine the vertical scrolling region — rows outside it stay pinned, rows inside scroll.
- SCOSC / SCORC — Save / Restore cursor (CSI s / u)
\x1b[s (save) \x1b[u (restore)CSI-style save (s) and restore (u) of cursor position — distinct from ESC 7 / ESC 8 (DECSC / DECRC).
- CHT — Cursor Forward Tabulation (CSI I)
\x1b[NIAdvance the cursor N tab stops — the parameterized form of pressing Tab.
- DA — Device Attributes (CSI c / CSI > c)
\x1b[c (primary DA) \x1b[>c (secondary DA)Ask the terminal what kind of VT it is — primary (CSI c) returns features, secondary (CSI > c) returns model + firmware.
- DSR — Device Status Report (CSI 5n / CSI 6n)
\x1b[5n (status request) \x1b[6n (cursor pos request)Ask for terminal status (5n) or the current cursor position (6n) — the reverse channel TUIs use to size the terminal.
- DECRQM — Request Mode Status (CSI ? Ps $ p)
\x1b[?Ps$pAsk the terminal whether a specific DEC private mode is enabled — used for feature detection at runtime.
- ICH — Insert Character (CSI Pn @)
\x1b[Pn@Shift the rest of the current line right by N cells and blank-fill the gap — the primitive vim's insert mode is built on.
- DCH — Delete Character (CSI Pn P)
\x1b[PnPDelete N cells at the cursor and shift the rest of the line left to fill the gap — the inverse of ICH.
- IL — Insert Line (CSI Pn L)
\x1b[PnLOpen N blank lines at the cursor row and push subsequent lines down within the scrolling region — vim's 'O' command primitive.
- DL — Delete Line (CSI Pn M)
\x1b[PnMRemove N lines starting at the cursor row and pull subsequent lines up within the scrolling region — vim's 'dd' command primitive.
- ECH — Erase Character (CSI Pn X)
\x1b[PnXErase N cells in place at the cursor — same shape as DCH but the rest of the line does NOT shift left.
- REP — Repeat Preceding Character (CSI Pn b)
\x1b[PnbRepeat the most-recently-emitted printing character N times — a bandwidth-saver for runs of identical glyphs.
- VPA — Vertical line position absolute (CSI d)
\x1b[<row>dMove the cursor to an absolute row, keeping the current column.
- HVP — Horizontal and vertical position (CSI f, alias of CUP)
\x1b[<row>;<col>fMove the cursor to absolute (row, col) — semantically identical to CUP but uses final byte `f` instead of `H`.
- XTWINOPS — Window manipulation (CSI Ps ; Ps ; Ps t)
\x1b[<Ps>t or \x1b[<Ps>;<Pa>;<Pb>txterm's window-manipulation family — resize, minimise, raise/lower, query size, push/pop title.
- DECSED / DECSEL — Selective erase display / line (CSI ? Ps J / CSI ? Ps K)
\x1b[?<Ps>J (DECSED) \x1b[?<Ps>K (DECSEL)Erase only the unprotected cells in the display (DECSED) or current line (DECSEL) — the private-mode siblings of ED / EL.
- SL / SR — Scroll left / right (CSI Ps SP @ / CSI Ps SP A)
\x1b[<Ps> @ (SL) \x1b[<Ps> A (SR)Scroll the screen content left (SL) or right (SR) by Ps columns — the horizontal counterpart of CSI S / CSI T.
- DECSCA — Select character protection attribute (CSI Ps " q)
\x1b[<Ps>"qMark subsequently-written cells as DECSED/DECSEL-protected (Ps=1) or unprotected (Ps=0/2).
- DECSLRM — Set left and right margins (CSI Pl ; Pr s)
\x1b[<Pl>;<Pr>sConstrain horizontal cursor movement + scrolling to columns Pl…Pr — the horizontal counterpart of DECSTBM.
- XTPUSHCOLORS / XTPOPCOLORS / XTREPORTCOLORS — Palette stack (CSI # P / # Q / # R)
\x1b[#P (push) \x1b[#Q (pop) \x1b[#R (report)Save / restore / inspect xterm's ANSI palette via a process-local stack — useful for TUIs that mutate the palette temporarily.
- DECDC / DECIC — Delete / insert column (CSI Pn ' ~ / CSI Pn ' })
\x1b[<Pn>'~ (DECDC) \x1b[<Pn>'} (DECIC)Delete (DECDC) or insert (DECIC) Pn columns at the cursor — the column-oriented counterparts of DL (CSI Pn M) and IL (CSI Pn L).
- XTMODKEYS — Modify keyboard reporting (CSI > Pp ; Pv m)
\x1b[><Pp>;<Pv>mSwitch xterm's modifyKeyboard / modifyCursorKeys / modifyFunctionKeys / modifyOtherKeys resources at runtime — the foundation for Ctrl+letter, Alt+letter disambiguation.
- XTSMTITLE / XTRMTITLE — Set / reset title display modes (CSI > Ps ; … t / T)
\x1b[><Ps>;<Ps>…t (set) \x1b[><Ps>;<Ps>…T (reset)Switch how xterm interprets / returns window-title and icon-name strings — hex vs UTF-8 encoding, truncation, set-vs-query behaviour.
- DECSWBV / DECSMBV — Set warning / margin bell volume (CSI Ps SP t / CSI Ps SP u)
\x1b[<Ps> t (DECSWBV) \x1b[<Ps> u (DECSMBV)Adjust the audio volume of the C0 BEL (DECSWBV) and the right-margin warning bell (DECSMBV) — almost universally ignored by modern emulators.
- SGR / urxvt mouse encoding — Mouse-report wire formats (CSI M / CSI < / CSI)
\x1b[M<Cb><Cx><Cy> (legacy) \x1b[<<Cb>;<Cx>;<Cy>M|m (SGR ?1006) \x1b[<Cb>;<Cx>;<Cy>M (urxvt ?1015)The three on-wire formats a terminal uses to report mouse events: legacy CSI M Cb Cx Cy, modern SGR ?1006, and urxvt ?1015 — what's actually in the input stream after DECSET ?100x enables tracking.
- XTVERSION — Report terminal name and version (CSI > Pp q)
\x1b[>0q (query) reply: \x1bP>|<name> <version>\x1b\\Ask the terminal for a human-readable name + version string — the modern alternative to DECDA for feature detection in tools like Helix, Zellij, Neovim.
- CSI ? Ps n — Private DSR (extended status queries)
\x1b[?<Ps>nDEC private Device Status Reports — extended cursor position (?6 DECXCPR with page), printer / UDK / locator / macro-space / memory-checksum status.
- HPA / HPR / VPR — Position absolute & relative (CSI ` / CSI a / CSI e)
\x1b[<col>` (HPA) \x1b[<n>a (HPR) \x1b[<n>e (VPR)ECMA-48's row/col-preserving cursor moves — HPA (absolute column), HPR (relative column), VPR (relative row) — completing the trio anchored by VPA.
- XTSMGRAPHICS — Sixel / ReGIS / color-register capacity query + set (CSI ? Pi ; Pa ; Pv S)
\x1b[?<Pi>;<Pa>;<Pv>SRead / set the terminal's graphics limits — number of sixel color registers, sixel graphics area, ReGIS area. The standard knob for image-aware TUIs to size their bitmaps.
- DECSASD / DECSSDT — Status display routing & type (CSI Ps $ } / CSI Ps $ ~)
\x1b[<Ps>$} (DECSASD) \x1b[<Ps>$~ (DECSSDT)Pick which display surface (main vs status line) receives subsequent output (DECSASD), and what the status line is for (DECSSDT) — DEC VT320's split-screen status row.
- XTQMODKEYS — Query modifyKeys current value (CSI ? Pp m)
\x1b[?<Pp>mAsk xterm what the current modifyKeyboard / modifyCursorKeys / modifyFunctionKeys / modifyOtherKeys value is — the companion query for XTMODKEYS.
- XTPUSHSGR / XTPOPSGR / XTREPORTSGR — SGR stack (CSI Ps + p / + q / + r)
\x1b[#{ (XTPUSHSGR, alt: CSI Pm + p) \x1b[#} (XTPOPSGR, alt: CSI + q) \x1b[+r (XTREPORTSGR)Save / restore / inspect the current SGR attributes via a stack — the SGR analogue of XTPUSHCOLORS for the palette.
- DECSCPP — Select columns per page (CSI Pn $ |)
\x1b[80$| (80 cols) \x1b[132$| (132 cols)Resize the active page to 80 or 132 columns — the data-side request that DECCOLM expresses as a private mode toggle.
- Secondary DA reply decoder — `CSI > Pp ; Pv ; Pc c` model / firmware / cart
\x1b[>Pp;Pv;PccDecoder reference for the secondary Device Attributes reply — what each Pp model code means and how kitty / wezterm / alacritty / iTerm2 / Ghostty encode their version in Pv.
- XTSAVE / XTRESTORE — Save / restore DEC private mode (`CSI ? Pm s` / `CSI ? Pm r`)
\x1b[?<Pm>s (save) \x1b[?<Pm>r (restore)Stash one or more DEC private mode states on a stack, then restore them later — the foundation tmux / screen / fzf use to safely toggle mouse / alt-screen / paste modes without trampling user prefs.
- DECSCL — Select conformance level (`CSI Pl ; Pc " p`)
\x1b[<Pl>;<Pc>" pChoose VT100 / VT200 / VT300 / VT400 / VT500 conformance level — controls which subset of escape sequences the terminal honours, plus 7-bit vs 8-bit C1 emission. Implicitly performs a hard reset (RIS) first.
- DECSTR side-effects — exactly which modes `\x1b[!p` resets
\x1b[!pReference enumeration of every DEC mode / attribute that DECSTR (soft reset) restores to its default — what gets cleared, what survives, and where xterm vs kitty vs iTerm2 diverge.
- DECRPM decoder — parsing the DECRQM reply (`CSI ? Ps ; Pm $ y`)
\x1b[?<Ps>;<Pm>$y (private) \x1b[<Ps>;<Pm>$y (ANSI)How to read the `CSI ? Ps ; Pm $ y` (and `CSI Ps ; Pm $ y`) reply that DECRQM returns — the `Pm` value tells you whether the mode is set / reset / always-set / always-reset / unrecognised.
- DEC locator suite — DECELR / DECEFR / DECSLE / DECRQLP (mouse / locator events)
\x1b[<Pn>;<Pu>'z \x1b[<Pm>'{ \x1b[<Pt>;<Pl>;<Pb>;<Pr>'w \x1b[<Ps>'|The original DEC pointing-device protocol (predates xterm SGR mouse modes by a decade). Four sequences enable, filter, select, and query locator events; modern interactive UIs use SGR mouse modes (`?1000` + `?1006`) instead.
- DECREQTPARM / DECREPTPARM — Request and report terminal parameters (`CSI Ps x`)
\x1b[<Ps>xVT100-era legacy probe — ask the terminal for its serial-line parameters (parity, bit-count, baud, clock multiplier, flags). Predates DA / DA2 / XTVERSION; almost never the right tool now, but xterm and most modern emulators still answer with synthetic defaults.
- DECCARA / DECRARA — Change / Reverse attributes in rectangular area (`CSI Pt;Pl;Pb;Pr;Ps;… $ r` / `$ t`)
\x1b[<Pt>;<Pl>;<Pb>;<Pr>;<Ps>;…$r (DECCARA) \x1b[<Pt>;<Pl>;<Pb>;<Pr>;<Ps>;…$t (DECRARA)Set or XOR SGR attributes across a rectangle of cells without rewriting any character data — the rectangular-attribute siblings of the copy/fill/erase ops in `dec-rect-ops`.
- DECPS — Play Sound (`CSI Pv ; Pd ; Pn1 [; …] , ~`)
\x1b[<Pv>;<Pd>;<Pn1>[;<Pn2>…],~DEC VT520 musical-tone playback — `Pv` volume, `Pd` duration, then one or more `Pn` MIDI-style note numbers. Niche but implemented by xterm, WezTerm, Ghostty, mlterm; the only ANSI way to make the terminal beep at a specific pitch.
- DECTABSR — Tab Stop Report (`CSI 2 $ w`)
\x1b[2$wAsk the terminal to dump its current horizontal tab stops as a DCS report. Closes the round-trip story: set via HTS (`esc-hts`), clear via TBC (`csi-tbc`), query the current set via DECTABSR.
- DECRQCRA / DECCKSR — Request Checksum of Rectangular Area (`CSI Pi;Pg;Pt;Pl;Pb;Pr*y`)
\x1b[Pi;Pg;Pt;Pl;Pb;Pr*y reply \x1bP<Pi>!~<hex4>\x1b\\Ask the terminal to compute a 16-bit checksum over a rectangle of cells (`CSI Pi;Pg;Pt;Pl;Pb;Pr*y`); reply arrives as DCS DECCKSR (`\x1bP<Pi>!~<hex4>\x1b\\`). The xterm vttest / ConPTY conformance pin.
- DECLL — Load LEDs (`CSI Ps q`, no SP intermediate)
\x1b[Ps qTurn the keyboard's front-panel L1–L4 LEDs on / off (`CSI Ps q`). Surviving in Linux-console terminfo as `KEYBOARD_LED 1/2/3/4` — modern emulators silent no-op except xterm + Linux console.
- DECCRA / DECFRA / DECERA / DECSERA — Copy / Fill / Erase / Selective-erase rectangular area
\x1b[<Pts>;<Pls>;<Pbs>;<Prs>;<Pps>;<Ptd>;<Pld>;<Ppd>$v DECCRA\n\x1b[<Pch>;<Pt>;<Pl>;<Pb>;<Pr>$x DECFRA\n\x1b[<Pt>;<Pl>;<Pb>;<Pr>$z DECERA\n\x1b[<Pt>;<Pl>;<Pb>;<Pr>${ DECSERAThe four content-side rectangle ops missing from the DEC rect family — copy a block, fill it with a glyph, erase to space, or erase only non-protected cells. Pairs with DECCARA / DECRARA (attribute-side) and DECSACE (block-vs-stream toggle).
- DECSACE — Select Attribute Change Extent (`CSI Ps * x`)
\x1b[<Ps>*xToggle whether DECCARA / DECRARA treat their rectangle as a literal cell block (default) or as a stream from start-position to end-position. The content-side rect ops (DECCRA / DECFRA / DECERA / DECSERA) are unaffected.
- CSI Ps i — Media Copy (MC) — printer-on / printer-off / print line
\x1b[0i / \x1b[4i / \x1b[5i / \x1b[?4i / \x1b[?5iECMA-48 §8.3.82 control that historically routed terminal output to an attached printer. Survives today as the 'print screen' hook on xterm/mlterm, the IBM-3270 emulator pass-through, and as private-mode `CSI ? 4 / 5 i` auto-print toggles consumed by `expect`-style automation.
- DECRQDE / DECRPDE — Request / Report Displayed Extent (`CSI " v` / `" w`)
\x1b["v DECRQDE (request)\n\x1b[<Ph>;<Pw>;<Pml>;<Pmt>;<Pmp>"w DECRPDE (reply)VT420+ pagination query — ask the terminal how many rows / columns are currently displayed and where the scroll window sits inside the page memory. Reply tells the host the visible viewport without relying on `tput lines / cols`.