SU / SD — Scroll up / down
Scroll the screen contents up (SU) or down (SD) by N lines without moving the cursor.
Byte forms
Every common string-literal form so you can paste-and-search either direction.
\x1b[NS (scroll up) \x1b[NT (scroll down)\033[1S / \033[1T\e[1S / \e[1TESC [ N S / T1b 5b <N> 53 / 54Description
ECMA-48 §8.3.147 (SU) and §8.3.113 (SD). Final byte S = SU (Scroll Up), T = SD (Scroll Down). Byte sequences \x1b[<N>S and \x1b[<N>T respectively; N defaults to 1 if omitted. Both shift the *scrolling region's* contents by N rows and fill the exposed rows with blanks — SU \x1b[<N>S makes the top N rows disappear and N blank rows appear at the bottom (the inverse of how a new line of text scrolls the screen on its own), SD \x1b[<N>T does the opposite. The crucial detail: the cursor stays put. Unlike CUU / CUD (cursor-move) which move the cursor without affecting contents, SU / SD move the *contents* without touching the cursor — they are content-scroll primitives, not cursor moves. If DECSTBM (\x1b[<top>;<bot>r, see decstbm) has restricted the scrolling region, only those rows shift; rows outside the region stay frozen, which is what TUIs use to keep a status bar in place while a log viewport rolls.
Portability — universal across modern emulators: xterm, iTerm2, kitty, alacritty, wezterm, gnome-terminal, Konsole, Ghostty, Windows Terminal, ConPTY 1809+, Linux console. The biggest parsing gotcha is that final byte T is also used by the xterm mouse-tracking protocol (CSI Pe ; Px ; Py ; Pv ; Ph T for highlight tracking, see xterm-ctlseqs DECSET ?1001). Modern terminals disambiguate by parameter count — single-parameter T is SD, multi-parameter T is mouse tracking — but parsers that ingest unknown CSI sequences from the wild should handle both shapes. Some legacy emulators implemented SU but not SD; if SD \x1b[T doesn't visibly work on a target terminal, the fallback is to insert blank rows at the top of the region with IL (\x1b[<N>L, see csi-il). tmux forwards SU / SD unmodified, respecting the inner pane's scrolling region.
The use-case split: SU is the workhorse — TUIs use it for content scrolling without disturbing the cursor (log viewers, paged output, animated dashboards where new data rolls into view but the cursor needs to stay on a status line). SD is rarer; its main use is "rewind" animations or implementing scroll-back-up in a custom less-style viewer when you don't want the full redraw cost. Compare LF (\n, see c0-controls) which scrolls the *whole* screen when emitted at the bottom of the *unrestricted* region — SU lets you scroll inside a DECSTBM-defined region without touching rows outside it, which is the property that makes split-pane TUIs possible. Compare also IL / DL (csi-il / csi-dl) which insert / delete lines *at the cursor row* — SU / SD operate on the whole region uniformly, IL / DL operate on one position. Related: decstbm (DECSTBM — sets the scrolling region SU / SD operate within), cursor-move (CUU / CUD — cursor-only counterparts that don't touch content), csi-il (IL — the per-row insert-line companion to region-wide SD).
Spec citation: ECMA-48 §8.3.147 (SU) / §8.3.113 (SD)
Parameters
| S | scroll up by N rows |
| T | scroll down by N rows |
Examples
printf 'top\nmid\nbot\033[2S' # scroll region up 2import sys; sys.stdout.write('\x1b[1S')fmt.Print("\x1b[1S")process.stdout.write('\x1b[1S')printf("\x1b[1S");Used in
Real-world tools that emit this sequence — anchors the bytes to commands you've already used.
- less, more pagers`d` (half-page down) and `u` (half-page up) emit SU / SD to scroll the viewport without redrawing the status line
- vim, neovim window scrolling`<C-d>` / `<C-u>` and `<C-e>` / `<C-y>` map to SU / SD inside a DECSTBM-restricted region so the status line stays pinned
- htop, btop, glances dashboardsanimated update of the process list rolls rows up via SU while the header row stays frozen outside the scroll region
- tmux, GNU screen split-pane redrawseach pane runs an inner DECSTBM region; SU / SD per pane stays inside that pane without leaking into the divider or other panes
- ncurses wgetch — refresh loop emits SU to scroll the inner window without clearing the surrounding chrome
Frequently asked
Short answers to the questions developers actually search for this sequence.
- What's the difference between
\x1b[1Sand just emitting\nat the bottom row? - Two things. (1) Cursor: SU keeps the cursor put; LF at the bottom row moves it down (which the terminal then clamps to the bottom, but the row counter does change in some emulators' internal model). (2) Region awareness: SU operates strictly inside the DECSTBM scroll region — rows outside the region stay frozen. LF only scrolls the unrestricted region; if you've narrowed the scroll region with
\x1b[<top>;<bot>rand the cursor is parked outside it, LF behaviour is implementation-defined and often surprising. TUIs that want "roll the log viewport up one row but keep my status bar and cursor pinned" pick SU for both properties at once. - Why is
\x1b[T(SD) sometimes interpreted as a mouse-tracking report? - Final byte
T(0x54) is overloaded. With one parameter it's SD —\x1b[<N>Tscrolls the region down N rows. With five parameters (\x1b[<Pe>;<Px>;<Py>;<Pv>;<Ph>T) it's the xterm highlight-tracking mouse report from DECSET?1001. Modern emulators disambiguate by parameter count, but ad-hoc parsers that just matchCSI ... Twithout counting parameters mishandle one or the other. If you're writing such a parser, count the;separators before dispatching. If you're emitting SD into a terminal that has highlight-tracking enabled by some prior app and never disabled it, prefer the IL fallback (\x1b[<N>Lat the top row of the region) to sidestep the ambiguity entirely.
Terminal support
- xterm
- yes
- Linux console (fbcon)
- yes
- macOS Terminal.app
- yes
- iTerm2
- yes
- Windows Terminal
- yes
- cmd.exe / ConPTY
- yes
- kitty
- yes
- alacritty
- yes
- WezTerm
- yes
- Ghostty
- yes
- GNOME Terminal
- yes
- Konsole
- yes
- tmux
- yes
- GNU screen
- yes
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes |
Related sequences
In the family cookbook
CSI cookbook · 5. Margins & scroll region — DECSTBM `r` and DECSLRM `s`