Skip to main content
ansicode

DECTCEM ?25 — Show/hide cursor

Show or hide the text cursor.

Byte forms

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

\\x1b[\x1b[?25h (show) \x1b[?25l (hide)
\\033[\033[?25h / \033[?25l
\\e[\e[?25h / \e[?25l
ESC [ESC [ ? 2 5 h / l
hex1b 5b 3f 32 35 68 / 6c

Description

DEC Text Cursor Enable Mode. \x1b[?25h shows the text cursor, \x1b[?25l hides it — the ? prefix marks this as a DEC private mode (not an ECMA-48 SGR or CSI sequence) and the trailing h / l is the SET / RESET final-byte pair shared by every DEC private mode (?7h/l DECAWM, ?12h/l cursor blink, ?1049h/l alt-screen, etc.). Honoured by every emulator in the support matrix above. The cursor's *position* is unaffected — only the rendered caret toggles — so hiding the cursor before a multi-line redraw and showing it afterward avoids the visual jitter of the caret skipping across redrawn text, which is the primary use case for progress bars and full-screen TUIs.

The single biggest pitfall — and probably the most common terminal-state bug — is leaving ?25l set when your program exits abnormally. A panic, a kill -9, a SIGINT before your handler runs, or an unhandled exception in a CLI flow leaves the user's shell with no visible prompt cursor. The user then has to run tput cnorm (the terminfo cap for ?25h) or reset to recover it. Always register a cleanup handler that re-shows the cursor: bash trap "printf '\\x1b[?25h'" EXIT INT TERM; Python signal.signal(signal.SIGINT, lambda *_: (sys.stdout.write('\\x1b[?25h'), sys.exit(130))); Go defer fmt.Print("\\x1b[?25h") paired with an os/signal handler that re-emits before exit. The stuck-cursor-hidden pitfall under /pitfalls documents the recovery path in detail. Visibility is also orthogonal to dec-cursor-shape (DECSCUSR \x1b[N q) and dec-cursor-blink — you can hide a steady block cursor and re-show it later as a blinking bar; the three settings compose independently.

Re-show the cursor with \x1b[?25h — the surgical complement of ?25l. Inside alt-screen mode (?1049h) the visibility setting is per-screen on most emulators: hiding the cursor in alt-screen does not propagate back to the primary buffer on exit, so an alt-screen TUI that hides the cursor doesn't strictly need to re-show it before the ?1049l exit (though belt-and-braces code emits both anyway). The terminfo caps for portability are civis (hide → \x1b[?25l on xterm-256color) and cnorm (show → \x1b[?25h); tput civis / tput cnorm in shell scripts is the canonical way to spell this without a hard $TERM assumption. Related: dec-cursor-shape for shape, dec-cursor-blink for blink, cursor-save-restore for snapshotting and restoring position alongside visibility.

Spec citation: xterm-ctlseqs (DECTCEM)

Examples

bash
printf '\033[?25l'; sleep 2; printf '\033[?25h'
python
import sys; sys.stdout.write('\x1b[?25l')
go
fmt.Print("\x1b[?25l")
javascript
process.stdout.write('\x1b[?25l')
c
printf("\x1b[?25l");

Used in

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

  • npm, pnpm install spinnershide on spinner start, restore on completion
  • ora (Node), cli-spinners
  • htop, btop full-screen TUIs
  • less — hides cursor on page
  • vim, neovim — depending on guicursor setting

Frequently asked

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

My cursor disappeared and won't come back. What do I run?
printf '\033[?25h' re-shows it. A TUI crashed before re-emitting it — your shell inherited the hidden state. If that doesn't work, reset (or stty sane) clears every terminal mode including cursor visibility. See the stuck-cursor-hidden pitfall for the prevention recipe (signal handlers that re-emit \x1b[?25h on exit).
Is \x1b[?25h / \x1b[?25l the same as \x1b[?12h / \x1b[?12l?
No. ?25 toggles cursor visibility (show / hide the glyph). ?12 toggles cursor blinking (steady / blinking, where supported). They're independent — you can hide a blinking cursor, or show a steady one. For finer cursor-shape control (block / underline / bar, blinking / steady) use DECSCUSR (\x1b[N q) — see dec-cursor-shape.

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

DEC cookbook · 1. The `?` prefix — DECSET vs SM