# Select Graphic Rendition (SGR)

> Set the colors and attributes of the characters written after it.

- **Sequence:** `CSI Pm m`
- **Defaults:** Pm = 0
- **ECMA-48:** [§8.3.117 SGR – Select Graphic Rendition, p. 61](https://archive.org/details/ecma-48-5th-edition-june-1991/page/n74/mode/1up)
- **DEC STD 070:** [§5.6.2 Select Graphic Rendition, p. 5-103](https://archive.org/details/bitsavers_decstandar0VideoSystemsReferenceManualDec91_74264381/page/n357/mode/1up)
- **VT220:** [§4.9.1 Select Graphic Rendition (SGR)](https://vt100.net/docs/vt220-rm/chapter4.html#S4.9.1)
- **VT510:** [SGR—Select Graphic Rendition](https://vt100.net/docs/vt510-rm/SGR.html)

Set how the characters written from now on look. `Pm` is a list of
parameters, applied in order, so one SGR can set several things at once.
`CSI m` with no parameters is `CSI 0 m`, which resets everything.

| Parameter | Sets | Undone by |
| --- | --- | --- |
| `1` | bold | `22` |
| `2` | faint | `22` |
| `3` | italic | `23` |
| `4` | underline | `24` |
| `5` | blink | `25` |
| `7` | inverse | `27` |
| `8` | invisible | `28` |
| `9` | strikethrough | `29` |
| `30`–`37`, `90`–`97` | foreground, from the 16 basic colors | `39` |
| `40`–`47`, `100`–`107` | background, likewise | `49` |
| `38;5;N`, `48;5;N` | color `N` of the 256-color palette | `39`, `49` |
| `38;2;R;G;B`, `48;2;R;G;B` | a direct RGB color | `39`, `49` |

The 256-color and direct forms come from ITU T.416, which separates their
parts with colons: `38:2::R:G:B`, with an empty field for a color space
nobody uses. Terminals accept both. Colons also carry underline styles, as
`4:2` double, `4:3` curly, `4:4` dotted and `4:5` dashed, in the
terminals that have them. A default xterm does not: it
accepts colons only in `38` and `48`, and skips any other parameter that
has them, so `4:3` changes nothing
([`charproc.c`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L4332-L4350)).
libghostty-vt draws the styles, so the case for them is a known difference.

Attributes belong to the characters written, not to the cells: moving the
cursor does not change them, and writing over a cell replaces its attributes
with the current ones.

A default xterm also follows an old PC convention: bold text in one of the
eight basic colors, `30` to `37`, is drawn in the bright version of it,
color 8 to 15, and that is the color it keeps and reports
([`charproc.c`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/charproc.c#L1118-L1129), under the `boldColors`
resource, on by default). So `CSI 1 ; 31 m` gives bold text in color 9, and
DECRQSS reports the rendition as `0;1;91`. libghostty-vt keeps color 1, so
that case is a known difference.

## Support

| Terminal | Version | Support | Notes |
| --- | --- | --- | --- |
| VT220 | [manual](https://vt100.net/docs/vt220-rm/), 2nd ed., 1984 | Partly | [§4.9.1 Select Graphic Rendition (SGR)](https://vt100.net/docs/vt220-rm/chapter4.html#S4.9.1): `0`, `1`, `4`, `5`, `7` and their resets; no colors |
| VT510 | [manual](https://vt100.net/docs/vt510-rm/), 1st ed., 1993 | Partly | [SGR](https://vt100.net/docs/vt510-rm/SGR.html): adds invisible, `8` and `28`; no colors, faint, italic or strikethrough |
| xterm | patch 412, [xterm-411a](https://github.com/ThomasDickey/xterm-snapshots/tree/xterm-411a) | Yes | bold with a basic color takes the bright one (`boldColors`); no underline styles: it takes subparameters only for `38` and `48` |
| libghostty-vt | [0f171f6](https://github.com/ghostty-org/ghostty/tree/0f171f650a1cbbd6df4a2573b6b0c7de57cc6d90) | Yes | keeps the basic color under bold (SGR-1) and draws underline styles (SGR-4) |
| kitty | 0.49.1, [run in a VM](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/kitty.json) | Yes | passes the 3 cases that show it working |
| pyte | 0.8.2, [run as a library](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/pyte.json) | Partly | fails SGR-3 of the 3 cases that show it working |
| xterm.js headless | 6.0.0, [run as a library](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/xtermjs.json) | Yes | passes the 3 cases that show it working |
| alacritty_terminal | 0.26.0, [run as a library](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/alacritty.json) | Yes | passes the 3 cases that show it working |
| ConEmu | build 230724, its [documentation](https://conemu.github.io/en/AnsiEscapeCodes.html) | Partly | no `8`, `9` or colon forms; `2` unsets bold, and `3` is italic or inverse; [ANSI escape codes](https://conemu.github.io/en/AnsiEscapeCodes.html) |
| rxvt-unicode | 9.31, [run in a VM](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/urxvt.json) | Yes | passes the 2 cases that show it working |
| VTE | 0.84.1, [run as a library](https://git.jcollie.dev/jeff/control-codes/src/branch/main/emulators/results/vte.json) | Yes | passes the 2 cases that show it working |

## Validation

### SGR-1: Bold and a color

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e[1;31m  # bold red: xterm makes it bright red
A
\e[0m
B
```

Expected screen:

```text
|AB___|
attr 1,1 bold fg=9
attr 1,2 plain
```

### SGR-2: Undoing one attribute

Input, one step per line:

```text
\e[1;3;4m # bold, italic, underline
A
\e[23m    # not italic
B
```

Expected screen:

```text
|AB___|
attr 1,1 bold italic underline
attr 1,2 bold -italic underline
```

### SGR-3: 256 colors and direct color

Input, one step per line:

```text
\e[38;5;208m
A
\e[38;2;90;180;250m
B
\e[48:2::200:100:0m
C
```

Expected screen:

```text
|ABC__|
attr 1,1 fg=208
attr 1,2 fg=#5ab4fa
attr 1,3 fg=#5ab4fa bg=#c86400
```

### SGR-4: Underline styles are skipped

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e[4:3m   # curly, skipped by xterm
A
\e[4:2m   # double, the same
B
\e[24m
C
```

Expected screen:

```text
|ABC__|
attr 1,1 -underline
attr 1,2 -underline
attr 1,3 -underline
```

### SGR-5: Inverse

Input, one step per line:

```text
\e[32;7m
A
```

Expected screen:

```text
|A____|
attr 1,1 inverse fg=2
```

---

This is the Markdown version of <https://control-codes.page/csi/sgr/>. On that page every validation case runs live in libghostty-vt, the terminal emulation core of Ghostty, compiled to WebAssembly.

The validation cases are written in the notation described in <https://control-codes.page/notation/index.html.md>.
