Customize
CSS variables
Load tty.css first, then override its effective custom properties. The tables below reflect the variables actually consumed by the current stylesheet.
Scope and themes
Palette parameters live on :root and a root override applies across modes. For direct semantic color overrides, match each active selector you support: :root for light, :root[data-theme="dark"] for explicit dark, and :root[data-theme="auto"] inside prefers-color-scheme: dark for automatic dark. tty.css does not currently implement local, subtree themes.
:root {
--tty-accent: #ffd166;
--tty-accent-hover: #ffc233;
--tty-accent-fg: #2b1800;
}
:root[data-theme="dark"] {
--tty-accent: #ffe08a;
--tty-accent-hover: #ffeaad;
--tty-accent-fg: #241400;
}
@media (prefers-color-scheme: dark) {
:root[data-theme="auto"] {
--tty-accent: #ffe08a;
--tty-accent-hover: #ffeaad;
--tty-accent-fg: #241400;
}
}Recheck text, focus, control, selection, and status contrast in every theme after changing colors. See theme selection and accessibility responsibilities.
Create a color palette
Use the palette playground for generated colors, or Monokai for full overrides. The complete token tables are below.
Color tokens
tty.css requires OKLCH. The 19 generated semantic roles use the parameter-derived formulas below, with no support guard or hex fallback. Direct semantic overrides may use any CSS color format supported by your target browsers. Status tokens remain independent mode-specific hex colors:
| Token | Light default | Dark and auto-dark default | Used for |
|---|---|---|---|
--tty-success | #15803d | #4ade80 | Valid states and optimum meters |
--tty-warning | #b45309 | #fbbf24 | Suboptimum meters |
--tty-danger | #c83232 | #fb7185 | Invalid states, deletion, and poor meters |
Public palette parameters
These defaults apply across all modes. Override them on :root after tty.css; no support guard is needed. Direct semantic token overrides remain supported and can be mixed with parameters.
| Parameter | Default (all modes) | Role mapping |
|---|---|---|
--tty-accent-hue | 65 | Hue of accents, links, general focus, and selection |
--tty-accent-chroma | 0.125 | Chroma of those accent roles, with role-specific factors |
--tty-neutral-hue | 260 | Hue of canvas, surfaces, text, borders, code, control focus, and shadows |
--tty-neutral-chroma | 0.025 | Chroma of those neutral roles, with role/mode-specific factors |
Status colors and SVG icon images are independent of these parameters. Arbitrary hue/chroma choices are not guaranteed accessible; test each mode and state. See the Colors guide for parameter-only, direct, and mixed palettes.
Effective OKLCH role formulas
Every row evaluates to oklch(L C H). Here A means var(--tty-accent-chroma), N means var(--tty-neutral-chroma), and hue is the corresponding public hue parameter. Multiplication denotes calc(). These describe the implementation, not additional public knobs.
Light (including an omitted theme attribute) uses the light column. Explicit dark uses the dark column. Auto uses light unless prefers-color-scheme: dark matches, when it uses dark. Modes select internal --_tty-* lightness values and neutral chroma factors; those internal values are not public API.
| Semantic token | L light / dark | C light / dark | H parameter |
|---|---|---|---|
--tty-bg | 98.5% / 18% | N × 0.2 / N × 1.2 | neutral hue |
--tty-surface | 100% / 23% | N × 0 / N × 1.2 | neutral hue |
--tty-surface-muted | 96.5% / 27% | N × 0.4 / N × 1.6 | neutral hue |
--tty-fg | 21% / 98% | N × 1.6 / N × 0.2 | neutral hue |
--tty-fg-muted | 48% / 78% | N / N | neutral hue |
--tty-border | 85% / 43% | N / N | neutral hue |
--tty-border-strong | 21% / 98% | N × 1.6 / N × 0.2 | neutral hue |
--tty-accent | 83% / 83% | A / A | accent hue |
--tty-accent-hover | 78% / 88% | A / A | accent hue |
--tty-accent-fg | 27% / 23% | A × 0.32 / A × 0.32 | accent hue |
--tty-link | 47% / 85% | A / A | accent hue |
--tty-link-hover | 40% / 80% | A / A | accent hue |
--tty-selection | 90% / 40% | A × 0.6 / A × 0.6 | accent hue |
--tty-selection-fg | 35% / 97% | A × 0.32 / A × 0.32 | accent hue |
--tty-code-bg | 21% / 13% | N × 1.6 / N × 1.6 | neutral hue |
--tty-code-fg | 98% / 98% | N × 0.2 / N × 0.2 | neutral hue |
--tty-focus | 56% / 85% | A / A | accent hue |
--tty-control-focus | 37% / 85% | N / N | neutral hue |
--tty-control-shadow | 55% / 43% | N / N | neutral hue |
--tty-success, --tty-warning, and --tty-danger have no derived formula: use their mode-specific hex defaults in the color table above.
Typography and font policy
| Token | Default | Used for |
|---|---|---|
--tty-font | "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace | Body, controls, code, and component headings |
--tty-font-display | var(--tty-font) | Page headings and reading-layout headings |
--tty-reading-width | 72ch | Maximum width of paragraphs and other reading text |
tty.css names JetBrains Mono first but does not load fonts. It uses JetBrains Mono only when already installed and otherwise follows the system monospace fallback stack.
Override both font tokens when body and display text should differ. Supply complete fallback stacks, verify all required weights, and test control sizing, code, wrapping, and layout in fallback fonts. A ch-based reading width changes with the selected font.
:root {
--tty-font: "IBM Plex Mono", ui-monospace, monospace;
--tty-font-display: "IBM Plex Sans", system-ui, sans-serif;
--tty-reading-width: 68ch;
}Layout and shape tokens
| Token | Default | Used for |
|---|---|---|
--tty-container | 72rem | Body landmark and .container maximum width |
--tty-grid-min | 17rem | Minimum auto-fitting .grid column width, capped by available width |
--tty-radius | 0.2rem | General controls, code, menus, and disclosures; joined search controls retain pill-shaped ends |
--tty-frame-radius | 0 | Article, fieldset, dialog, and exposed tab-frame corners, independent of controls. Joined tab edges stay square. |
--tty-border-width | 1px | Quiet borders, dividers, and tooltip borders |
--tty-frame-width | 2px | Strong component frames and custom controls |
--tty-shadow-x | 0.5rem | Horizontal decorative frame shadow |
--tty-shadow-y | 0.5rem | Vertical decorative frame shadow |
--tty-shadow-color | var(--tty-border-strong) | Frame-shadow color, independent of mask shapes |
--tty-shadow-opacity | 0.6; 1 for .strong-shadow | Frame-shadow opacity |
--tty-shadow-pattern | Embedded 4×4 SVG: Standard; inverse Dense for .strong-shadow | Repeating SVG mask with two staggered rectangular marks |
--tty-shadow-pattern-size | 4px 4px | Mask tile size, not offset; use 3px 3px for Fine |
--tty-progress-pattern | Embedded 4×4 Dense SVG, matching Dense frame shadows | Optional repeating fill mask for progress.textured[value] |
--tty-progress-pattern-size | 4px 4px | Textured progress mask tile size |
--tty-control-shadow-size | 0.125rem | Button and form-control shadow offset |
--tty-control-height | 2.5rem | Minimum height of buttons and single-line controls |
Changing a dimension can affect many components at once. Keep border widths non-negative, preserve usable target sizes, and check narrow layouts before shipping.
Set --tty-grid-min on an individual grid for a local override; see the live grid example.
<div class="grid" style="--tty-grid-min: 14rem">
<article><h3>Primary</h3><p>Healthy</p></article>
<article><h3>Replica</h3><p>Healthy</p></article>
</div>:root {
--tty-container: 80rem;
--tty-radius: 0;
--tty-frame-width: 2px;
--tty-shadow-x: 0.35rem;
--tty-shadow-y: 0.35rem;
--tty-control-shadow-size: 0.1rem;
--tty-control-height: 2.75rem;
}For a component-scoped adjustment, override --tty-frame-width, --tty-shadow-x, and --tty-shadow-y on an application class instead of :root. These also work with the optional frame treatments; double borders use 3× the frame width, while strong shadows keep the configured offsets.
The four mask-shadow tokens are optional overrides, not required :root declarations. They are shared by articles, fieldsets, tabs, table wrappers, and dialogs. Their defaults resolve on each shadow pseudo-element so local border colors are respected, and explicit overrides also win on .strong-shadow. SVG masks supply shapes only; CSS supplies color. For a custom --tty-shadow-pattern: url(...), the SVG alpha defines transparency. See texture examples.
The two progress pattern tokens are separate optional overrides, not aliases of the shadow tokens. Their defaults resolve where consumed, with no :root aliases. Set them on progress.textured to customize its mask; SVG alpha supplies the shape while CSS color supplies the currentColor fill. The default Dense mask matches frame shadows but is configured independently. See the native progress example.
On .overflow-auto table wrappers, frame treatments style the table frame and its shadow within the wrapper padding. Dropdown and tooltip overlays are shadowless and do not support frame treatments; dropdown lists need no wrapper. Small solid control shadows, radio states, and validation treatments remain intentional.
--tty-spaceis not defined or consumed by the current stylesheet. It is not part of the effective customization API, and overriding it has no effect; use ordinary application spacing rules instead.
Icon tokens
| Token | Default | Used for |
|---|---|---|
--tty-icon-search | Embedded 16×16 SVG data URL | Search inputs |
--tty-icon-date | Embedded 16×16 SVG data URL | Date, month, and week inputs |
--tty-icon-time | Embedded 16×16 SVG data URL | Time inputs |
--tty-icon-datetime | Embedded 16×16 SVG data URL | Local date-time inputs |
These icons are decorative CSS backgrounds; control labels provide meaning. Their SVG strokes remain fixed at #526174 in light and #aab7c8 in dark/auto-dark; changing palette parameters or --tty-fg-muted does not recolor the images. Override them with a CSS url(), including a percent-encoded data URL if embedding SVG. Match the 16×16 view box and test light, dark, and disabled states. Firefox and forced-colors mode intentionally use native picker presentation for date and time controls.
:root {
--tty-icon-search: url("/assets/search.svg");
--tty-icon-date: url("/assets/calendar.svg");
--tty-icon-time: url("/assets/clock.svg");
--tty-icon-datetime: url("/assets/date-time.svg");
}Low-specificity overrides
Most framework selectors use :where(), so an application class normally wins without !important. Load overrides after tty.css and target the smallest stable application hook. Some structural selectors and composition classes have normal specificity, so inspect the actual rule when an override does not win.
.billing-card {
border-style: dashed;
}
button.danger {
background: var(--tty-danger);
color: var(--tty-surface);
}
.settings-form input {
border-radius: 0;
}Avoid overriding generated internals such as browser-specific range and meter pseudo-elements unless your product owns the resulting cross-browser test matrix.