Every color Druk renders — editor background, tab strip, status bar, git gutter marks, and every syntax token — comes from the active theme. A theme is a plain TypeScript object with two sections:Documentation Index
Fetch the complete documentation index at: https://mintlify.com/letstri/druk/llms.txt
Use this file to discover all available pages before exploring further.
ui for chrome colors and syntax for tree-sitter capture groups. Adding one means copying an existing file, replacing the palette, and registering the result in THEMES. It appears in the command palette automatically, with no other wiring needed.
Steps
Copy an existing theme file
src/themes/github-dark.ts is the most complete reference — it covers every ui key and a full syntax map. Copy it to src/themes/my-theme.ts:name field:src/themes/my-theme.ts
Cite the upstream palette source in the file header, as every built-in theme does. The GitHub Dark theme links to
https://github.com/primer/github-vscode-theme; Catppuccin links to the Catppuccin spec; Everforest links to palette.md in the Everforest repository. The comment makes it easy to check a hex value against the upstream and to update the theme when the palette ships a new version.Adjust the ui and syntax objects
Replace every hex value in
ui and syntax with colors from your chosen palette.For ui, map the palette’s neutral surface tones to the background keys and its text tones to the foreground keys. Only currentLine and indentGuide are usually absent from published palettes — blend those from bg yourself (see Blending currentLine and indentGuide below).For syntax, follow the scheme’s own highlighting guide where one exists. Catppuccin ships a style guide; Everforest ships palette.md with per-group recommendations; Solarized’s vim colorscheme is the canonical reference for that palette. Matching those assignments is what makes the theme feel recognizable.The GitHub Dark theme is a complete example of what a finished ui + syntax pair looks like:src/themes/github-dark.ts
Register the theme in src/themes/index.ts
Add an import and an entry to The key is what users type in the command palette to select the theme — keep it lowercase and hyphen-separated. The
THEMES:src/themes/index.ts
name field on the theme object is the human-readable label the palette displays.Restart Druk (or rebuild if running from source). Open the command palette (F1), type appearance or your theme’s name, and select it from the list.Theme structure
ATheme has two top-level fields: ui and syntax.
ui — chrome colors
ui is a ThemeUi object. Every key must be present; the TypeScript type enforces this at compile time. The keys group into a few categories:
Backgrounds
| Key | What it paints |
|---|---|
bg | Main editor background |
panelBg | Floating panels and overlays (must stay opaque) |
barBg | Tab strip and title bars |
statusBg | Status bar background |
| Key | What it paints |
|---|---|
text | Primary foreground — file content, active labels |
dim | Secondary text — inactive tabs, line numbers |
faint | Tertiary — scrollbar, gutter marks |
statusFg | Status bar text |
| Key | What it paints |
|---|---|
accent | Highlighted links, focused borders |
activeTabFg | Active tab label |
inactiveTabFg | Inactive tab label |
treeSelectedBg | Selected row in the file tree (focused) |
treeFocusBg | Selected row in the file tree (unfocused) |
cursor | Editor cursor color |
scrollbar | Scrollbar thumb |
gutter | Line number column |
folder | Folder icon color |
| Key | What it paints |
|---|---|
currentLine | Background fill on the line the cursor is on |
indentGuide | Indent guide column tint |
| Key | What it paints |
|---|---|
dirty | Unsaved-change indicator, warning tint |
error | Error indicator, error tint |
gitAdded | Git added-line mark |
gitModified | Git modified-line mark |
gitDeleted | Git deleted-line mark |
syntax — token colors
syntax maps tree-sitter capture group names to style objects. Each style can have fg (hex color string), bg, bold, italic, and underline fields — all optional.
You don’t need to list every capture group. Sub-scopes fall back to their parent: if type.builtin isn’t defined, Druk uses the style for type instead. Omitting a group entirely costs nothing — it simply renders unstyled.
The capture groups the bundled themes cover: comment, keyword, keyword.operator, operator, string, escape, number, boolean, constant, function, function.method, function.builtin, constructor, type, type.builtin, namespace, variable, variable.builtin, variable.member, property, attribute, tag, label, punctuation, punctuation.bracket, punctuation.delimiter, punctuation.special, embedded, error, and the markup.* family.
Derived surface colors
UiColors extends ThemeUi with three keys Druk computes automatically — you never set these in your theme file:
sidebarBg— set topanelBgnormally, or'transparent'when thetransparentsetting is on.solidBg— always the theme’s ownbg, regardless of transparency. Used when blending diagnostic tint colors, where a mix with"transparent"is not a valid color.solidBarBg— always the theme’s ownbarBg, for the same reason.
Blending currentLine and indentGuide
Published palettes almost never name these two tones. Blend them offbg by hand — a small step toward the nearest mid-tone works well for most palettes:
currentLine and indentGuide are distinct from bg — they must not be identical, or the cursor row and indent stops become invisible.
How setTheme() works
setTheme() replaces syntaxTheme rather than merging into it. This is intentional: themes don’t all define the same capture groups, and a leftover group from the previous theme would render in the wrong palette — near-invisible text when the switch flips from light to dark or vice versa.
src/themes/index.ts
ui is a Solid store — syntaxTheme is a plain object
ui is created with createStore. Solid components never re-render on their own — reading ui.bg inside JSX is what subscribes that render spot to future changes. If ui were a plain object, every color on screen would become stale after a theme switch and never update.
syntaxTheme, by contrast, is a plain object. It is only read when the syntax style table is rebuilt (on theme switch and on first paint), so reactivity adds no value there.
Indent guides
Indent guides ride the same pipeline as syntax highlights:computeHighlights appends one indent.guide capture per indent stop, and the style for that capture comes from ui.indentGuide via the syntax style table. There is no separate color key to set — indentGuide in ui covers it.
Registration example
A complete registration, as it would appear insrc/themes/index.ts:
src/themes/index.ts