Themes¶
EasyBar supports file-based themes.
A theme is a TOML file that defines shared color tokens. Those tokens are used as visual defaults for the bar, native built-ins, popups, and other themed surfaces.
Themes control appearance only. Layout, ordering, grouping, enabled state, formats, filters, and behavior stay in config.toml.
Configure a theme¶
Select a theme in config.toml:
[theme]
name = "default"
themes_dir = "~/.config/easybar/themes"
name is the theme file name without .toml.
Examples:
default -> default.toml
tokyo-night -> tokyo-night.toml
my-theme -> my-theme.toml
themes_dir is the custom theme directory.
Switch themes from the menus¶
You can switch themes live from either EasyBar menu:
right-click the bar -> Theme -> <theme name>
menu bar icon -> Theme -> <theme name>
Selecting a theme immediately updates theme.name in config.toml and reloads EasyBar. Comments,
whitespace, and unrelated settings are preserved.
The menus list themes bundled with EasyBar and .toml themes found in the configured themes_dir.
Lookup order¶
EasyBar resolves themes in this order:
1. user theme: themes_dir/<name>.toml
2. bundled theme: EasyBar.app/Contents/Resources/Themes/<name>.toml
3. error if the theme does not exist
A user theme overrides a bundled theme with the same name.
Example:
~/.config/easybar/themes/default.toml
wins over the bundled default.toml.
Default theme¶
The default bundled theme is:
[theme]
name = "default"
This resolves to:
default.toml
The complete default config also uses this theme name.
Bundled themes¶
Bundled themes live in the repository root themes/ directory. That root directory is the source of truth for bundled theme files.
SwiftPM does not automatically package arbitrary root-level directories into EasyBar.app. For that reason, local runs and release builds must go through the project Makefile. The Makefile copies the root themes/ directory into the app bundle before launching or packaging the app:
EasyBar.app/Contents/Resources/Themes/
The bundled themes directory should contain at least:
themes/
└── default.toml
Additional bundled themes may also live there, for example:
themes/
├── default.toml
├── dracula.toml
├── everforest-dark.toml
├── frappe.toml
├── gruvbox-dark.toml
├── latte.toml
├── macchiato.toml
├── mocha.toml
├── nord.toml
├── rose-pine.toml
├── solarized-dark.toml
└── tokyo-night.toml
The Makefile should verify that default.toml exists after copying themes into the app bundle.
Bundled themes are not copied into ~/.config/easybar/themes, because user theme files should stay user-owned and should not become stale copies of bundled files. Instead they are baked into the app bundle.
For local development, prefer:
make run
For release-style packaging, prefer:
make bundle
Avoid relying on plain swift run EasyBar for theme testing, because it does not stage the root themes/ directory into the app bundle.
Custom themes¶
Create a custom theme in your configured themes_dir:
mkdir -p ~/.config/easybar/themes
$EDITOR ~/.config/easybar/themes/my-theme.toml
Then select it:
[theme]
name = "my-theme"
themes_dir = "~/.config/easybar/themes"
Reload EasyBar:
easybar config reload
Theme file format¶
[colors]
background = "#111111"
surface = "#1a1a1a"
surface_elevated = "#2b2b2b"
surface_hover = "#202020"
text = "#ffffff"
text_secondary = "#d0d0d0"
text_tertiary = "#c0c0c0"
muted = "#6c7086"
muted_secondary = "#8a8a8a"
outside_month = "#6e738d"
accent = "#91d7e3"
accent_secondary = "#89B4FA"
accent_soft = "#8bd5ca"
success = "#a6e3a1"
success_secondary = "#a6da95"
warning = "#f9e2af"
orange = "#fab387"
error = "#f38ba8"
danger = "#FF0000"
border = "#333333"
border_strong = "#444444"
border_subtle = "#00000000"
selection_text = "#0B1020"
selection_background = "#89B4FA"
transparent = "#00000000"
overlay_outline = "#000000F0"
overlay_text = "#FFFFFFFF"
today_button_border = "#3F2F6B"
Required color tokens¶
Every complete theme should define the full semantic palette:
| Token | Purpose |
|---|---|
background |
Main bar and popup background. |
surface |
Normal widget or inactive surface background. |
surface_elevated |
Focused, active, or raised surface background. |
surface_hover |
Hover or highlighted surface background. |
text |
Primary text color. |
text_secondary |
Secondary body or label text color. |
text_tertiary |
Tertiary text color for quieter labels. |
muted |
Secondary, inactive, or unavailable text color. |
muted_secondary |
Secondary muted tone for softer supporting content. |
outside_month |
Calendar text color for days outside the month. |
accent |
Accent color for highlights and secondary details. |
accent_secondary |
Secondary accent for supporting highlights. |
accent_soft |
Softer accent for subtle emphasis. |
success |
Positive or healthy status color. |
success_secondary |
Secondary positive color for supporting signals. |
warning |
Warning status color. |
orange |
Orange status color for low or degraded states. |
error |
Error or critical status color. |
danger |
Strong danger color for urgent attention. |
border |
Normal border color. |
border_strong |
Emphasized border color. |
border_subtle |
Subtle or transparent border color. |
selection_text |
Text color drawn on selected surfaces. |
selection_background |
Background color used for selected surfaces. |
transparent |
Fully transparent color, usually #00000000. |
overlay_outline |
Overlay outline color with alpha. |
overlay_text |
High-contrast overlay glyph or text color. |
today_button_border |
Border color for the calendar today button. |
Color references¶
Config color fields can reference theme tokens:
[bar.colors]
background = "theme.background"
border = "theme.transparent"
[builtins.time.style]
text_color = "theme.text"
background_color = "theme.surface"
border_color = "theme.border"
Theme references use this form:
theme.<token>
Examples:
theme.background
theme.surface
theme.surface_elevated
theme.surface_hover
theme.text
theme.text_secondary
theme.text_tertiary
theme.muted
theme.muted_secondary
theme.outside_month
theme.accent
theme.accent_secondary
theme.accent_soft
theme.success
theme.success_secondary
theme.warning
theme.orange
theme.error
theme.danger
theme.border
theme.border_strong
theme.border_subtle
theme.selection_text
theme.selection_background
theme.transparent
theme.overlay_outline
theme.overlay_text
theme.today_button_border
Plain hex colors still work everywhere.
Lua widgets¶
Lua widgets receive the active theme through easybar.theme.
Use resolved colors when the widget should render a concrete hex value:
easybar.add(easybar.kind.item, "clock", {
label = {
string = os.date("%H:%M"),
color = easybar.theme.colors.text,
},
})
Use theme references when a node color field should stay tied to the current theme:
easybar.add(easybar.kind.item, "clock", {
color = easybar.theme.ref.text,
background = {
color = easybar.theme.ref.surface,
},
})
easybar.theme.ref.<token> always mirrors the supported theme token names.
Override theme colors¶
You can override individual theme tokens in config.toml:
[theme]
name = "default"
[theme.colors]
accent = "#8aadf4"
error = "#ff6b6b"
This keeps the selected theme and changes only the listed tokens.
Override widget colors¶
Explicit widget config always wins over theme defaults.
[theme]
name = "default"
[builtins.battery.colors]
critical = "#ff0000"
Here the battery critical color uses #ff0000, even if the theme has a different error color.
What belongs in a theme¶
Good theme content:
- shared color tokens
- surface colors
- text colors
- status colors
- border colors
Do not put behavior or layout in theme files:
enabledpositionordergroup- date or time formats
- polling intervals
- calendar filters
- widget-specific behavior
Troubleshooting¶
Theme not found¶
If you see:
theme 'default' was not found in ~/.config/easybar/themes or bundled themes
check that one of these files exists:
~/.config/easybar/themes/default.toml
EasyBar.app/Contents/Resources/Themes/default.toml
For bundled themes, make sure the repository root contains the selected theme file:
themes/default.toml
Then rebuild or run through the Makefile so the root themes/ directory is copied into the app bundle. Use make run for local development and make bundle for a release-style app bundle.
Both targets should package bundled themes into:
EasyBar.app/Contents/Resources/Themes/
Bundled app-owned resources are staged separately under:
EasyBar.app/Contents/Resources/EasyBar/
├── Lua/
├── Events/
└── ThemeTokens/
Themes intentionally stay at Contents/Resources/Themes/ because they are selected and overridden through the user-facing [theme] configuration.
Plain swift run EasyBar is not enough for bundled theme testing unless you have separately staged the root themes directory into the app bundle resource location.
Theme changes do not apply¶
Reload config:
easybar config reload
If watch_config = false, EasyBar will not reload automatically.
A widget ignores the theme¶
Check whether that widget has an explicit color in config.toml.
Explicit widget colors override theme defaults.