# Omarchy theming Omarchy themes live under `themes//` in the source tree, with optional user themes under `~/.config/omarchy/themes//`. A theme normally starts with a `colors.toml`; Omarchy generates the rest of the theme files from `default/themed/*.tpl` when `omarchy-theme-set ` runs. ## Theme activation flow `omarchy-theme-set ` builds a clean staging directory at `~/.config/omarchy/current/next-theme`: 1. Copy the first-party theme from `themes//`. 2. Overlay any user theme files from `~/.config/omarchy/themes//`. 3. If needed, generate `colors.toml` from `alacritty.toml`. 4. Run `omarchy-theme-set-templates` to render templates into the staging theme. 5. Move the staging theme into `~/.config/omarchy/current/theme` and notify the running shell. Template rendering only happens when the staged theme has `colors.toml`. Existing files are never overwritten by a template, so a hand-written `themes//shell.toml` or `hyprland.lua` wins over `default/themed/shell.toml.tpl` or `hyprland.lua.tpl`. User templates in `~/.config/omarchy/themed/*.tpl` are processed before the built-in templates. If a user template has the same output filename as a built-in template, the built-in output is skipped. ## `colors.toml` `colors.toml` provides the palette keys used by templates. Common keys are: ```toml foreground = "#a9b1d6" background = "#1a1b26" accent = "#7aa2f7" color1 = "#f7768e" color4 = "#7aa2f7" ``` Any key can be referenced from a template with `{{ key }}`. The shell also uses a few semantic palette keys directly: - `foreground` - `background` - `accent` — preferred when present; otherwise some places fall back to `color4` - `urgent` / `color1` ## Template placeholders Templates are plain files ending in `.tpl`. `omarchy-theme-set-templates` replaces placeholders with values from `colors.toml`. ### Color placeholders For a color key such as `accent = "#7aa2f7"`: | Placeholder | Output | |-------------|--------| | `{{ accent }}` | `#7aa2f7` | | `{{ accent_strip }}` | `7aa2f7` | | `{{ accent_rgb }}` | `122,162,247` | ### Color mixing `mix`, `mix_strip`, and `mix_rgb` blend two hex colors by a fraction or percentage: ```text {{ mix background foreground 15% }} {{ mix_strip background accent 0.35 }} {{ mix_rgb color0 color7 50 }} ``` ### Gradient helpers Some theme keys can be either a solid color or a Hyprland-style gradient: ```toml hyprland_active_border = "rgba(33ccffee) rgba(00ff99ee) 45deg" ``` Gradient helper placeholders understand those values: | Helper | Use | Example output | |--------|-----|----------------| | `{{ hypr_gradient hyprland_active_border accent }}` | Hyprland Lua config | `{ colors = { "rgba(33ccffee)", "rgba(00ff99ee)" }, angle = 45 }` | | `{{ shell_gradient hyprland_active_border accent }}` | shell border tokens | `rgba(33ccffee) rgba(00ff99ee) 45deg` | | `{{ gradient_start hyprland_active_border accent }}` | flat-color-only consumers | `#33ccff` | The second argument is a fallback. For example, `{{ shell_gradient hyprland_active_border accent }}` means: use `hyprland_active_border` if the theme defines it; otherwise use `accent`. The helper does not choose the first color unless you use `gradient_start`. ## `shell.toml` `shell.toml` contains shell surface roles, control states, spacing, typography, and bar sizing. The default generated file comes from `default/themed/shell.toml.tpl`. Themes can override the entire generated file by shipping `shell.toml`, or just one section by shipping `shell.
.toml`. For example, `shell.lock.toml` replaces only the `[lock]` section after the default `shell.toml` has been generated: ```toml text = "#ffffff" placeholder = "#ffffff" border = "#ffffff" ``` The filename decides the target section, so the `[lock]` header is optional. The running shell reads `shell.toml` into two QML singletons: - `Color` for palette and surface roles like `Color.menu.border`. - `Style` for controls, spacing, font scale, corner radius, and bar sizing. ### Borders Shell border tokens accept either a solid color or a gradient in the same key: ```toml [notifications] border = "#7aa2f7" ``` or: ```toml [notifications] border = "rgba(33ccffee) rgba(00ff99ee) 45deg" ``` Do not add a separate `border-gradient` key for new themes. The parser still accepts `border-gradient` and `*-border-gradient` for compatibility with older configs, but the canonical form is the border key itself. Border alphas apply to solid borders and to every gradient stop: ```toml [notifications] border = "rgba(33ccffee) rgba(00ff99ee) 45deg" border-alpha = 0.8 ``` If a color stop already includes alpha, the stop alpha and `border-alpha` are combined. ### Border widths Border widths accept CSS-style lists: ```toml border-width = 2 # all sides border-width = "2 4" # top/bottom, right/left border-width = "2 4 6" # top, right/left, bottom border-width = "2 4 6 8" # top, right, bottom, left ``` Per-side keys override the list: ```toml [notifications] border-width = 2 border-width-left = 6 ``` That gives notifications a 2px border on the top, right, and bottom, and a 6px left edge. State-specific borders follow the same pattern. A selected menu row can use a different width from the card border: ```toml [menu] selected-border = "accent" selected-border-width = "1 1 1 4" ``` For state-specific surfaces such as lock and polkit, the token name prefixes the width key: ```toml [lock] border-active = "rgba(33ccffee) rgba(00ff99ee) 45deg" border-active-width-left = 6 ``` ### Control borders `[controls]` governs shared controls such as buttons, dropdowns, text fields, toggles, and cursor rows. Each state has a fill color, optional border value, border width, and border alpha: ```toml [controls] normal-color = "#a9b1d6" normal-border = "#a9b1d6" normal-border-width = 1 normal-border-alpha = 0.4 hover-cursor-color = "#a9b1d6" hover-cursor-border = "#a9b1d6" hover-cursor-border-width = 1 hover-cursor-border-alpha = 0.25 ``` The `*-border` keys can also be gradients: ```toml [controls] focus-border = "rgba(33ccffee) rgba(00ff99ee) 45deg" focus-border-width = "2 2 2 4" ``` Set a border width to `0` to keep the fill but remove that state border. ### Surface sections Common shell sections include: - `[bar]` - `[controls]` - `[popups]` - `[tooltip]` - `[notifications]` - `[launcher]` - `[menu]` - `[polkit]` - `[lock]` - `[image-picker]` - `[spacing]` - `[font]` Clipboard and emojis inherit menu tokens. Popups are used by bar flyouts, dropdowns, OSD, and popup cards. ## QML border API Plugin and shell QML should use `BorderSurface` for theme-aware borders: ```qml import qs.Commons import qs.Ui BorderSurface { color: Color.popups.background borderSpec: Border.surfaceSpec("popups", "border", Color.popups.border, 2) padding: Style.spacing.popupPadding Item { anchors.fill: parent anchors.topMargin: parent.contentTopInset anchors.rightMargin: parent.contentRightInset anchors.bottomMargin: parent.contentBottomInset anchors.leftMargin: parent.contentLeftInset } } ``` Use `Border.surfaceSpec(section, token, fallbackColor, fallbackWidth)` for shell theme tokens, `Border.controlSpec(state, foreground, accent)` for shared controls, and `Border.flat(color, width)` for a deliberate local border that should not be overridden by the active theme. `Color.
.border` is the flat first-stop color for consumers that cannot render full border specs. ## Hyprland templates Hyprland theme output is generated from `default/themed/hyprland.lua.tpl`. Use `hypr_gradient` for border values because Hyprland's Lua config wants a Lua string for solid colors and a Lua table for gradients: ```lua local active_border_color = {{ hypr_gradient hyprland_active_border accent }} ``` For a solid fallback this renders: ```lua local active_border_color = "#7aa2f7" ``` For a gradient it renders: ```lua local active_border_color = { colors = { "rgba(33ccffee)", "rgba(00ff99ee)" }, angle = 45 } ``` ## Adding or overriding theme files - Add palette values to `themes//colors.toml`. - Prefer generated files when the theme can be expressed with templates. - Add a hand-written file in `themes//` only when that theme needs to override the generated output entirely. - Add a new built-in template under `default/themed/.tpl` when every theme should generate that file. - Add a user-wide template under `~/.config/omarchy/themed/.tpl` when a local customization should apply across themes. When changing templates or theme helpers, run focused tests such as: ```bash ./test/cli ./test/shell ```