Skip to main content
ansicode

DECSCUSR — Cursor shape

Change the cursor shape: block, underline, or bar (with optional blink).

Byte forms

Every common string-literal form so you can paste-and-search either direction.

\\x1b[\x1b[N\x20q (N = 0..6)
\\033[\033[1 q
\\e[\e[1 q
ESC [ESC [ N SP q
hex1b 5b <N> 20 71

Description

DEC Set Cursor Style (DECSCUSR). Standard CSI with a SPACE (0x20) intermediate byte before the final q (0x71): \x1b[<N>\x20q. The parameter encodes both shape *and* blink in a single value — 0 = restore user default, 1 = blinking block (factory default), 2 = steady block, 3 = blinking underline, 4 = steady underline, 5 = blinking bar (vertical line), 6 = steady bar. First shipped in xterm patch 282 (Sep 2013); later adopted by every modern GUI emulator. The canonical editor-mode pattern: vim sets \x1b[6\x20q (bar) for insert mode and \x1b[2\x20q (block) for normal mode via its t_SI / t_EI terminal-string options; many shells (fish, zsh-vi-mode) do the same for vi command-line editing.

Portability — xterm, iTerm2, kitty, alacritty, wezterm, gnome-terminal, Konsole, Ghostty, Windows Terminal, ConPTY 1809+ all support DECSCUSR fully. Linux console is partial (the framebuffer driver honours shape changes but ignores the blink bit on most distros). Windows legacy cmd.exe is partial — pre-ConPTY ignored it; ConPTY forwards it. Apple Terminal.app added support late but works. The biggest authoring stumble is the SPACE intermediate byte: \x1b[6q (no space) is *not* DECSCUSR — without the SP intermediate the final q parses as a different (often DECSTBM-related) sequence and the cursor doesn't change at all. The byte sequence must be exactly ESC [ <N> SPACE q. terminfo capability Ss (set cursor style) is defined for DECSCUSR but most terminfo entries don't populate it, so apps tend to hard-code the byte sequence directly. tmux forwards DECSCUSR to the outer terminal correctly across modern versions.

Restore-on-exit is the durable cleanup. A crashed editor that never restored the user's preferred shape leaves the terminal stuck on whatever bar / underline DECSCUSR last set — surprising the user when they return to the shell prompt. The canonical cleanup is \x1b[0\x20q (parameter 0 = "restore user default") on exit, typically wired into the editor's t_EI or an atexit handler. The heavier hammer is DECSTR (\x1b[!p, see decstr-soft-reset) which resets DECSCUSR among other private modes without clearing the scrollback. Be aware that "user default" is terminal-defined — most emulators map parameter 0 to blinking block, but kitty / wezterm / iTerm2 honour a user-configured default, so the same \x1b[0\x20q can produce different shapes on different terminals — that's intended behaviour, not a bug. Related: cursor-visibility (DECTCEM ?25 — orthogonal: visibility vs shape, both need cleanup on crash), cursor-position (CUP — placement, the third cursor concern), dec-cursor-blink (DECSET ?12 — blink-only toggle that doesn't disturb the chosen shape, the alternative when you want to override blink without forcing a specific shape).

Spec citation: xterm-ctlseqs (DECSCUSR, CSI Ps SP q)

Parameters

0user-default cursor
1blinking block
2steady block
3blinking underline
4steady underline
5blinking bar
6steady bar

Examples

bash
printf '\033[6 q'   # vertical bar (insert mode)\nprintf '\033[2 q'   # block (normal mode)\nprintf '\033[0 q'   # restore default
python
import sys; sys.stdout.write('\x1b[6 q')
go
fmt.Print("\x1b[6 q")
javascript
process.stdout.write('\x1b[6 q')
c
printf("\x1b[6 q");

Used in

Real-world tools that emit this sequence — anchors the bytes to commands you've already used.

  • vim, neovim`guicursor` writes DECSCUSR per mode — block for normal, vertical bar for insert, underline for replace
  • fishdefault `fish_vi_cursor` swaps cursor shape on vi-mode transitions
  • zsh + zsh-vi-mode pluginblock on NORMAL, bar on INSERT — emitted from the line-init hook
  • bash with `bind 'set show-mode-in-prompt on'`vi-mode aware prompts emit DECSCUSR when switching command/insert
  • starship — `vicmd_symbol` companion that also sets cursor shape

Frequently asked

Short answers to the questions developers actually search for this sequence.

Why does \x1b[6q not change my cursor shape — but \x1b[6 q does?
DECSCUSR requires a SPACE (0x20) *intermediate* byte before the final q: the wire form is exactly ESC [ <N> SPACE q. Without the space, \x1b[6q parses as a different (DECSTBM-related) CSI and the cursor doesn't change at all. In \e-quoted shell strings remember the space — printf '\e[6 q' is correct, printf '\e[6q' is silently wrong.
Why does my cursor stay as a block after vim exits, instead of going back to a bar?
vim configures the cursor shape via t_SI / t_EI for *its own* insert / normal modes but doesn't restore the user's pre-vim shape on exit unless t_te is set to emit \x1b[0\x20q (DECSCUSR 0 = restore terminal default). Add let &t_EI = "\e[2 q" | let &t_te ..= "\e[0 q" to your .vimrc, or send \x1b[0\x20q from your prompt to repaint each new line. neovim handles this correctly out of the box since 0.4.

Terminal support

xterm
yes
Linux console (fbcon)
partial
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

Related sequences

In the family cookbook

CSI cookbook · 6. Insert / delete / cursor shape — IL / DL / ICH / DCH / ECH + DECSCUSR