Skip to main content
ansicode

CHA — Cursor horizontal absolute (column)

Move the cursor to column N of the current row (1-indexed).

Byte forms

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

\\x1b[\x1b[NG
\\033[\033[1G
\\e[\e[1G
ESC [ESC [ N G
hex1b 5b <N> 47

Description

ECMA-48 §8.3.9 — Cursor Horizontal Absolute (CHA). Final byte G, byte sequence \x1b[<N>G where N is the 1-based column. Sets the column without touching the row; N defaults to 1 if omitted (\x1b[G = "move to column 1"). The horizontal-only counterpart of VPA (\x1b[<N>d, vertical position absolute) and the column half of CUP (\x1b[<r>;<c>H, full row+column). The most common idiom is \x1b[1G\x1b[K (jump to column 1 + erase to end of line) — visually equivalent to \r\x1b[K on a CRLF terminal but with no line-feed semantics, which matters when the writer sits inside a DECSTBM scroll region or a noecho raw-mode TTY where \r could be interpreted unexpectedly.

Portability — universal. xterm, iTerm2, kitty, alacritty, wezterm, gnome-terminal, Konsole, Ghostty, Windows Terminal, ConPTY 1809+, and Linux console all support CHA. HPA (\x1b[<N>\, final byte 0x60 backtick) is the ECMA-48 §8.3.57 synonym with identical semantics — every terminal that accepts one accepts the other. Out-of-range column values clamp to the rightmost visible column (or the rightmost column of the DECSLRM left/right margin region when that's active on a margin-supporting emulator). The universal stumble is 1-based vs 0-based indexing: column 1 is the leftmost, not column 0. In xterm and most modern emulators \x1b[0G is treated as \x1b[1G because parameter 0` is interpreted as "use default" and the default for CHA is 1 — but relying on that is fragile, the spec-correct value for the leftmost column is 1. tmux passes CHA through unmodified.

No "close" — CHA is a stateless move, not a toggle. The redraw idiom is \x1b[1G\x1b[K<text>; for in-place spinners and progress bars, \x1b[<col>G positions at a known column and the writer follows up with text. Prefer CHA over \r when carriage returns might be filtered (cooked-mode TTYs that translate \r to CRLF, or a TUI that tracks column position independently of the terminal's own CR handling) and when you want the move to be visible to a parser that doesn't special-case \r. For absolute targeting where the row also matters, CUP (cursor-position, \x1b[r;cH) is one round-trip cheaper than CHA + VPA. Related: cursor-position (CUP — absolute row+column in one move), cursor-next-prev-line (CNL / CPL — vertical move that also forces column 1), erase-line (EL — partial / entire line erase, the natural pairing for redraw loops).

Spec citation: ECMA-48 §8.3.9 (CHA)

Examples

bash
printf 'progress:\033[20G50%%\033[1G' 
python
print('\x1b[20G50%')
go
fmt.Print("\x1b[20G50%")
javascript
process.stdout.write('\x1b[20G50%')
c
printf("\x1b[20G50%%");

Used in

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

  • tqdm, pip, npm download progress barsrate / ETA / percentage are positioned at fixed columns with `\x1b[<col>G` so the layout stays aligned regardless of file-name length
  • starship, oh-my-zsh, powerlevel10k right-promptsright-aligned segments compute `COLUMNS - len(content)` then emit CHA to jump to that column before writing
  • git rebase --interactive editor screensuses CHA + EL combos to redraw the highlighted commit line in place without disturbing surrounding context
  • whiptail, dialog (TUI form widgets)every form field places its label and input box at predetermined columns via CHA
  • fzf — search-result preview pane positions matched highlights via CHA before underlining the substring

Frequently asked

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

Why does \x1b[0G end up at column 1 instead of column 0?
Because CHA is 1-based — column 1 is the leftmost cell, there is no column 0. ECMA-48 §5.4 specifies that an SGR / cursor-positioning parameter value of 0 means "use the default", and the default for CHA is 1. So \x1b[0G, \x1b[1G, and \x1b[G (omitted) all land at the leftmost column. Spec-correct code emits \x1b[1G; relying on the 01 coercion works on xterm and every mainstream emulator but is undefined behaviour and will trip up strict parsers (some ECMA-48 conformance test suites flag it).
When should I use \x1b[1G instead of \r to return to column 1?
Three situations. (1) Raw-mode TTY where OPOST / onlcr is off — \r then has no special meaning the line discipline can mangle (it'd be passed through anyway, but you avoid surprise interaction with custom termios flags). (2) Inside a DECSTBM scroll region where you want column 1 of the *current* row without risking implicit scrolling — CHA is a pure column move, \r\n is two operations and the \n part may scroll. (3) When a parser downstream (a recorder, terminal-output linter, escape-aware paginator) doesn't special-case \r — emitting CHA makes the intent explicit as a CSI sequence. For ordinary cooked-mode shell output, \r is fine and byte-shorter; reach for \x1b[1G only when one of these matters.

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 · 2. Cursor movement — CUU / CUD / CUF / CUB + CUP + CHA / VPA