Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Augani/kael/llms.txt

Use this file to discover all available pages before exploring further.

Kael’s theme system is the single source of truth for every visual decision in your application. A Theme value holds five typed sub-structs — ThemeColors, ThemeTypography, ThemeSpacing, ThemeRadii, and ThemeShadows — and plugs directly into GPUI’s global state so that any component can read the active theme from any context. Changes propagate automatically: swap the global and every window refreshes.

Theme

Theme is the root struct. It derives Clone, Debug, PartialEq, serde::Serialize, and serde::Deserialize, and implements the Global marker trait so it can be stored with cx.set_global / cx.global.
rust
pub struct Theme {
    pub colors:     ThemeColors,
    pub typography: ThemeTypography,
    pub spacing:    ThemeSpacing,
    pub radii:      ThemeRadii,
    pub shadows:    ThemeShadows,
}
Theme::default() delegates to Theme::light().

Constructors

Theme::light()
fn() -> Theme
Returns the built-in light theme derived from Colors::light().
Theme::dark()
fn() -> Theme
Returns the built-in dark theme derived from Colors::dark().
Theme::for_appearance(window)
fn(&Window) -> Theme
Inspects window.appearance() and returns Theme::light() for WindowAppearance::Light or WindowAppearance::VibrantLight, and Theme::dark() for WindowAppearance::Dark or WindowAppearance::VibrantDark. Use this to match the OS preference when a window first opens.
rust
// In a window callback
let theme = Theme::for_appearance(&window);
cx.set_global(theme);

Parsing

Theme::from_json_str(input)
fn(&str) -> Result<Theme>
Deserializes a Theme from a JSON string. Returns an error if parsing fails.
Theme::from_toml_str(input)
fn(&str) -> Result<Theme>
Deserializes a Theme from a TOML string. Returns an error if parsing fails.
Theme::from_path(path)
fn(impl AsRef<Path>) -> Result<Theme>
Reads a file and deserializes it as JSON or TOML. The format is determined from the file extension (.json / .toml). For unknown extensions, Kael sniffs the content — trying JSON first if the trimmed content starts with {, otherwise TOML first — and returns both error messages if neither succeeds.
[colors]
background = "#101820"
surface    = "#19232d"
primary    = "#2563eb"
foreground = "#f9fafb"

[typography]
ui_font_family = ".SystemUIFont"
ui_font_size   = 14.0

Global state

Theme::init(cx)
fn(&mut App)
Installs the theme runtime into the app. You must call this once at startup, before any component reads the active theme.Theme::init does three things:
  1. Subscribes an observer on Theme global changes that calls sync_theme_colors and refreshes all windows.
  2. Sets the Theme global to Theme::default() if one is not already present.
  3. Syncs the initial GlobalColors from the current theme.
rust
fn main() {
    App::new().run(|cx| {
        Theme::init(cx);
        // Now cx.global::<Theme>() is available everywhere.
    });
}
cx.observe_theme_file calls Theme::init internally, so you do not need to call it separately when using hot-reload.

Hot-reload

App::observe_theme_file watches a JSON or TOML file and re-applies the theme every time the file changes on disk.
rust
cx.observe_theme_file("themes/my-theme.toml", |theme, cx| {
    cx.set_global(theme);
}).expect("failed to watch theme file");
The watcher normalizes the path to an absolute canonical form, watches the parent directory, and filters events to only those that match the target file (including renames). Parse errors are logged but do not crash the watcher.
The file watcher holds a subscription alive for the lifetime of the app. If you drop the returned Result value without checking it, a missing file will silently fail to start the watcher.

ThemeColors

Semantic color tokens mapped from the underlying Colors palette.
rust
pub struct ThemeColors {
    pub background:    Hsla,
    pub surface:       Hsla,
    pub primary:       Hsla,
    pub accent:        Hsla,
    pub muted:         Hsla,
    pub foreground:    Hsla,
    pub border:        Hsla,
    pub separator:     Hsla,
    pub selected_text: Hsla,
    pub error:         Hsla,  // #dc2626 in defaults
    pub warning:       Hsla,  // #f59e0b in defaults
    pub success:       Hsla,  // #16a34a in defaults
    pub custom:        BTreeMap<SharedString, Hsla>,
}
background
Hsla
The primary application background color.
surface
Hsla
The default elevated or contained surface color (maps from Colors::container).
primary
Hsla
The primary interactive emphasis color (maps from Colors::selected).
accent
Hsla
A secondary accent color for links or highlighted details (also maps from Colors::selected in the built-in palette).
muted
Hsla
The muted or disabled foreground color (maps from Colors::disabled).
foreground
Hsla
The default readable foreground color (maps from Colors::text).
border
Hsla
The shared border color.
separator
Hsla
The color used for dividers and separators.
selected_text
Hsla
The foreground color used on selected or primary-colored surfaces.
error
Hsla
The error status color. Defaults to #dc2626.
warning
Hsla
The warning status color. Defaults to #f59e0b.
success
Hsla
The success status color. Defaults to #16a34a.
custom
BTreeMap<SharedString, Hsla>
An open-ended map of project-specific color tokens. Serialize as a TOML table or JSON object under the custom key.
You can extend ThemeColors with arbitrary tokens via the custom map without forking the crate. Store token names as reverse-DNS strings (e.g. "com.myapp.sidebar-active") to avoid collisions.

ThemeTypography

Font settings for UI and code content.
rust
pub struct ThemeTypography {
    pub ui_font_family:   SharedString, // default: ".SystemUIFont"
    pub ui_font_weight:   FontWeight,   // default: FontWeight::NORMAL
    pub ui_font_size:     Pixels,       // default: px(14.)
    pub ui_line_height:   Pixels,       // default: px(20.)
    pub code_font_family: SharedString, // default: "Menlo"
    pub code_font_size:   Pixels,       // default: px(13.)
}
ui_font_family
SharedString
The font family for general UI text. Defaults to ".SystemUIFont", which resolves to the OS system UI font on every supported platform.
ui_font_weight
FontWeight
The default font weight for UI text. Defaults to FontWeight::NORMAL.
ui_font_size
Pixels
The base font size for UI text. Defaults to px(14.).
ui_line_height
Pixels
The default line height for UI text. Defaults to px(20.).
code_font_family
SharedString
The font family for code and monospace content. Defaults to "Menlo".
code_font_size
Pixels
The font size for code content. Defaults to px(13.).

ThemeSpacing

A six-stop spacing scale for layout gaps and component insets.
rust
pub struct ThemeSpacing {
    pub xs:  Pixels, // px(4.)
    pub sm:  Pixels, // px(8.)
    pub md:  Pixels, // px(12.)
    pub lg:  Pixels, // px(16.)
    pub xl:  Pixels, // px(24.)
    pub xxl: Pixels, // px(32.)
}
Use cx.global::<Theme>().spacing.md wherever you need a consistent gap between elements.

ThemeRadii

Corner radii for surfaces, cards, and pill shapes.
rust
pub struct ThemeRadii {
    pub sm:   Pixels, // px(4.)
    pub md:   Pixels, // px(8.)
    pub lg:   Pixels, // px(12.)
    pub xl:   Pixels, // px(16.)
    pub pill: Pixels, // px(999.) — effectively fully rounded
}

ThemeShadows

Three elevation levels expressed as BoxShadow tokens.
rust
pub struct ThemeShadows {
    pub sm: BoxShadow, // 0 1px  2px  0    rgba(0,0,0,0.10)
    pub md: BoxShadow, // 0 8px  24px -8px  rgba(0,0,0,0.14)
    pub lg: BoxShadow, // 0 16px 40px -12px rgba(0,0,0,0.18)
}
Each BoxShadow has fields color: Hsla, offset: Point<Pixels>, blur_radius: Pixels, spread_radius: Pixels, and inset: bool.

Reading the active theme from a component

rust
fn render(&self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
    let theme = cx.global::<Theme>();
    div()
        .bg(theme.colors.surface)
        .text_color(theme.colors.foreground)
        .rounded(theme.radii.md)
        .shadow(vec![theme.shadows.sm.clone()])
        .p(theme.spacing.md)
}

Updating the theme at runtime

rust
cx.update(|cx| {
    cx.set_global(Theme::dark());
});
// All windows refresh automatically via the sync_subscription observer.

Build docs developers (and LLMs) love