DECSTBM — Set Top/Bottom Margins (CSI r)
Define the vertical scrolling region — rows outside it stay pinned, rows inside scroll.
Byte forms
Every common string-literal form so you can paste-and-search either direction.
\x1b[T;Br\033[1;24r\e[1;24rESC [ T ; B r1b 5b <T> 3b <B> 72Description
Set Top and Bottom Margins. Final byte r (0x72); parameters are 1-based row numbers — T (top row, default 1) and B (bottom row, default = screen height). Once set, all scrolling — natural overflow at the bottom row, LF beyond row B, SU / SD (\x1b[NS / T), and the alt screen — operates only on rows T..B inclusive; rows above T and below B stay pinned. Sending \x1b[r (no parameters) resets to the full screen. After DECSTBM the cursor is moved to the home position of the active region (top-left). Every full-screen TUI uses this to keep a status bar (row 1 or N) frozen while the body scrolls. Pair with DECOM (?6h/l) to ALSO clip cursor addressing to the region.
Spec citation: xterm-ctlseqs (DECSTBM, CSI Ps ; Ps r)
Parameters
| T | top row, 1-based (default 1) |
| B | bottom row, 1-based (default = screen height) |
Examples
printf '\033[2;23r' # rows 2..23 scroll; 1 and 24 pinned\nprintf '\033[r' # reset to full screenimport sys; sys.stdout.write('\x1b[2;23r')fmt.Print("\x1b[2;23r")process.stdout.write('\x1b[2;23r')printf("\x1b[2;23r");Used in
Real-world tools that emit this sequence — anchors the bytes to commands you've already used.
- tmux, GNU screennarrow DECSTBM around the body region so the bottom status line is excluded from scroll — the bar stays pinned while panes scroll inside the carved region
- vim, neovim split windowseach window emits DECSTBM with its own top / bottom row pair so `<C-d>` / `<C-u>` scroll only that split, not the whole terminal
- htop, btop, glances dashboardsheader / footer rows are excluded from scroll; the process / chart region rolls within DECSTBM, header survives every redraw
- less, more — reserved status linethe bottom `:` prompt row is carved out of scroll via DECSTBM so `j` / `k` scrolling never overwrites the pager status line
- ncurses setscrreg(3X) / wsetscrreg(3X)the curses scroll-region API translates 1:1 to DECSTBM when the window is the full terminal — TUI libraries built on curses inherit DECSTBM semantics for free
Terminal support
- xterm
- yes
- Linux console (fbcon)
- yes
- macOS Terminal.app
- yes
- iTerm2
- yes
- Windows Terminal
- yes
- cmd.exe / ConPTY
- partial
- 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 | partial | 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`