helix-editor/helix
Themes
Themes are TOML files that map highlight scopes and UI element names to styles. Helix ships 200 themes in /.config/helix/themes/` and override bundled ones.runtime/themes/; user themes live in `
File format
# inherit and override
inherits = "monokai"
# token highlights
"keyword" = { fg = "magenta", modifiers = ["bold"] }
"keyword.control" = "magenta-bold" # palette reference
"function" = "blue"
"function.method" = { fg = "blue", modifiers = ["italic"] }
# UI elements
"ui.background" = { bg = "#1e1e1e" }
"ui.statusline" = { fg = "white", bg = "#252526" }
"ui.cursor.primary" = { fg = "black", bg = "yellow" }
# palette section maps named colors
[palette]
magenta = "#cc6699"The schema is implemented in helix-view/src/theme.rs. Each value is either a hex color ("#rrggbb"), a palette name, an ANSI named color, or a full table with fg, bg, modifiers, and underline fields.
Light/dark variants
The [theme] section in user config can specify both:
[theme]
light = "github_light"
dark = "ayu_mirage"Helix queries the terminal for its current background mode (via termina's OSC 11 query); if the terminal reports a mode, the matching theme is used. If the terminal can't tell, the optional fallback is used (default: dark).
The Mode enum and Config struct in theme.rs handle this logic.
Inheritance
A theme can inherit from another via inherits = "<name>". The loader walks the chain and merges fields with helix_loader::merge_toml_values (helix-loader/src/lib.rs). Cycles are detected and reported as errors.
Many bundled themes inherit from a base — e.g. all base16_* themes share a structure. This lets the project carry many themes without duplicating UI element keys.
Scope resolution
When the highlighter emits a scope like function.method.builtin, Theme::find_scope_index walks from the most specific to the least specific match:
function.method.builtin → function.method → function → (default)This matches tree-sitter's own scope semantics. UI keys (ui.background, ui.statusline, ui.menu, …) follow the same pattern.
Color formats
| Form | Example |
|---|---|
| Hex | "#1e1e1e" |
| Named palette | "magenta" (must be defined in [palette]) |
| ANSI named | "red", "bright-red" |
| RGB tuple | [30, 30, 30] |
default |
inherits the terminal default |
The Color enum in helix-view/src/graphics.rs carries all forms.
Modifiers
Bitflags from the Modifier struct in graphics.rs:
bold, dim, italic, underlined, slow_blink, rapid_blink, reversed, hidden, crossed_outunderline has its own field with style (Line, Curly, Dotted, Dashed, DoubleLine) and color so undercurl colors can differ from text colors. Undercurl is gated by editor.undercurl = true because not every terminal supports it.
Validation
cargo xtask theme-check (xtask/src/main.rs) loads every bundled theme through theme::Loader::load_with_warnings and fails CI if any theme produces a warning. Common warnings: unknown scope keys, palette references to nonexistent colors, inheriting from a missing parent.
The check runs in CI (see .github/workflows/build.yml Validate themes step).
Selecting a theme
:theme <name>— preview while typing in the picker; commit on Enter, revert on Esc. Implementation:theme_pickerincommands.rs; preview keeps the priorlast_themeon the editor.:config-reload— re-readsconfig.tomland applies the new theme.
Bundled themes
200+ themes ship under runtime/themes/, including ports of popular themes from other editors (Catppuccin, Tokyo Night, Solarized, GitHub, Gruvbox, Material). Contributing a new theme: add a <name>.toml and ensure cargo xtask theme-check passes.
See also
- features/syntax-highlighting — where scopes come from.
- packages/helix-view — the loader implementation.
- The user-facing book/src/themes.md — the canonical theme key reference.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.