Open-Source Wikis

/

Helix

/

Features

/

Themes

helix-editor/helix

Themes

Themes are TOML files that map highlight scopes and UI element names to styles. Helix ships 200 themes in runtime/themes/; user themes live in `/.config/helix/themes/` and override bundled ones.

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_out

underline 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_picker in commands.rs; preview keeps the prior last_theme on the editor.
  • :config-reload — re-reads config.toml and 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

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Themes – Helix wiki | Factory