App-Level Derivation
Most apps need tokens beyond what a generic theme provides — hover states, selection backgrounds, sidebar accents. Rather than requiring every theme author to define these, Opaline lets you derive app-specific tokens from the theme's existing palette.
The Pattern
Load a theme, inject your derived tokens, then activate it:
opaline::load_theme_by_name_with("catppuccin-mocha", |theme| {
let primary = theme.color("accent.primary");
// App-specific tokens derived from the theme palette
theme.register_default_token("sidebar.bg", primary.darken(0.85));
theme.register_default_token("sidebar.hover", primary.darken(0.75));
theme.register_default_token("tab.active", primary.lighten(0.1));
// App-specific styles
theme.register_default_style("sidebar_item", OpalineStyle::fg(primary).bold());
});After this call, the theme is the active global theme with your derived tokens available via theme.color("sidebar.bg") like any other token.
Token Registration
Default Registration
register_default_token and register_default_style use entry semantics — TOML-defined values win. This lets theme authors override your derivations when they want to:
// Only inserted if the theme doesn't already define "sidebar.bg"
theme.register_default_token("sidebar.bg", primary.darken(0.85));
// Only inserted if the theme doesn't already define "sidebar_item"
theme.register_default_style("sidebar_item", OpalineStyle::fg(primary));This is the recommended approach — it respects theme author intent.
Forced Registration
register_token and register_style unconditionally overwrite:
// Always overwrites, even if the theme defines this token
theme.register_token("sidebar.bg", primary.darken(0.85));
// Always overwrites the style
theme.register_style("sidebar_item", OpalineStyle::fg(primary));Use this sparingly — only when your app requires a specific derived value regardless of theme authoring.
Global State Functions
load_theme_by_name_with
Requires: global-state + builtin-themes
Load a builtin or discovered theme, run derivation, then set as the active global theme:
use opaline::load_theme_by_name_with;
load_theme_by_name_with("dracula", |theme| {
// Derive app tokens here
})?;load_theme_by_name_for_app_with
Requires: global-state + builtin-themes + discovery
Same as above, but also searches app-specific discovery paths (~/.config/<app>/themes/):
use opaline::load_theme_by_name_for_app_with;
load_theme_by_name_for_app_with("custom-theme", "myapp", |theme| {
// Derive app tokens here
})?;Defining a Derive Function
For apps with many derived tokens, extract the derivation into a named function:
fn derive_tokens(theme: &mut opaline::Theme) {
let primary = theme.color("accent.primary");
let bg = theme.color("bg.base");
// Navigation
theme.register_default_token("nav.bg", bg.darken(0.1));
theme.register_default_token("nav.hover", primary.darken(0.7));
theme.register_default_token("nav.active", primary);
// Status bar
theme.register_default_token("status.bg", bg.lighten(0.05));
theme.register_default_token("status.text", theme.color("text.secondary"));
}
// Use it everywhere you load themes
opaline::load_theme_by_name_with("nord", derive_tokens)?;With the ThemeSelector Widget
The ThemeSelector widget accepts a derivation callback so live preview includes your derived tokens:
let state = ThemeSelectorState::with_current_selected()
.with_derive(derive_tokens);Every theme preview will have your app-specific tokens applied, giving users an accurate look at what each theme will actually look like in your app.