Skip to main content
ansicode

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[\x1b[NS (scroll up) \x1b[NT (scroll down)
\\033[\033[1S / \033[1T
\\e[\e[1S / \e[1T
ESC [ESC [ N S / T
hex1b 5b <N> 53 / 54

Description

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

Sscroll up by N rows
Tscroll down by N rows

Examples

bash
printf 'top\nmid\nbot\033[2S'   # scroll region up 2
python
import sys; sys.stdout.write('\x1b[1S')
go
fmt.Print("\x1b[1S")
javascript
process.stdout.write('\x1b[1S')
c
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[1S and just emitting \n at 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>r and 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>T scrolls 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 match CSI ... T without 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>L at 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

Related sequences

In the family cookbook

CSI cookbook · 5. Margins & scroll region — DECSTBM `r` and DECSLRM `s`