Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Theming

Rinch’s theme system is CSS-variable-based, Mantine-inspired, and designed to be extended rather than fought against. Enable it with the theme feature (auto-enabled by components):

rinch = { git = "...", features = ["desktop", "theme"] }

Quick Start

fn main() {
    let theme = ThemeProviderProps {
        primary_color: Some("cyan".into()),
        default_radius: Some("md".into()),
        dark_mode: false,
        ..Default::default()
    };
    run_with_theme("My App", 800, 600, app, theme);
}

That’s it. Every component picks up your colors, radius, and spacing through CSS variables. Toggle dark_mode: true and the whole UI flips. All semantic colors — body background, text, borders, placeholders — adjust automatically.

Use run() instead of run_with_theme() to get the default theme (blue primary, light mode, small radius).

ThemeProviderProps

PropTypeDefaultDescription
primary_colorOption<String>"blue"Primary color name
primary_shadeOption<u8>6Shade index (0-9)
default_radiusOption<String>"sm"Border radius (xs, sm, md, lg, xl)
font_familyOption<String>System fontsPrimary font stack
font_family_monospaceOption<String>System monoMonospace font stack
dark_modeboolfalseDark mode

CSS Variables

The theme generates CSS custom properties you can use anywhere in your styles.

Colors

14 named palettes, each with 10 shades (0 = lightest, 9 = darkest):

var(--rinch-color-blue-0)     /* Lightest blue */
var(--rinch-color-blue-5)     /* Mid blue */
var(--rinch-color-blue-9)     /* Darkest blue */

var(--rinch-primary-color)    /* Primary at your chosen shade */
var(--rinch-primary-color-0)  /* Lightest primary */
var(--rinch-primary-color-9)  /* Darkest primary */

Available palettes: dark, gray, red, pink, grape, violet, indigo, blue, cyan, teal, green, lime, yellow, orange.

Semantic Colors

These flip automatically in dark mode:

var(--rinch-color-body)        /* Background (#f8f9fa light, dark gray dark) */
var(--rinch-color-text)        /* Primary text */
var(--rinch-color-dimmed)      /* Secondary text */
var(--rinch-color-border)      /* Borders */
var(--rinch-color-placeholder) /* Input placeholders */

Spacing

var(--rinch-spacing-xs)   /* 10px */
var(--rinch-spacing-sm)   /* 12px */
var(--rinch-spacing-md)   /* 16px */
var(--rinch-spacing-lg)   /* 20px */
var(--rinch-spacing-xl)   /* 32px */

Border Radius

var(--rinch-radius-xs)       /* 2px */
var(--rinch-radius-sm)       /* 4px */
var(--rinch-radius-md)       /* 8px */
var(--rinch-radius-lg)       /* 16px */
var(--rinch-radius-xl)       /* 32px */
var(--rinch-radius-default)  /* Whatever you set in ThemeProviderProps */

Typography

var(--rinch-font-size-xs)   /* 12px */
var(--rinch-font-size-sm)   /* 14px */
var(--rinch-font-size-md)   /* 16px */
var(--rinch-font-size-lg)   /* 18px */
var(--rinch-font-size-xl)   /* 20px */

var(--rinch-line-height-xs) /* 1.4 */
var(--rinch-line-height-md) /* 1.55 */

var(--rinch-font-family)
var(--rinch-font-family-monospace)

/* Heading sizes (h1-h6) */
var(--rinch-h1-font-size)
var(--rinch-h1-line-height)
var(--rinch-h1-font-weight)

Shadows

var(--rinch-shadow-xs)
var(--rinch-shadow-sm)
var(--rinch-shadow-md)
var(--rinch-shadow-lg)
var(--rinch-shadow-xl)

Using Theme Variables in Your Styles

#![allow(unused)]
fn main() {
rsx! {
    div { style: "
        background: var(--rinch-color-body);
        padding: var(--rinch-spacing-md);
        border-radius: var(--rinch-radius-default);
        box-shadow: var(--rinch-shadow-sm);
    ",
        h1 { style: "color: var(--rinch-primary-color);", "Themed!" }
        p { style: "color: var(--rinch-color-dimmed);", "Using theme variables." }
    }
}
}

Or use CSS shorthand props, which resolve scale values automatically:

#![allow(unused)]
fn main() {
rsx! {
    div { p: "md", m: "sm",  // -> var(--rinch-spacing-md), var(--rinch-spacing-sm)
        "Shorthand is nicer"
    }
}
}

Extending the Theme

Scoped Overrides

CSS variables cascade. Override them on a container div and everything inside picks up the change:

#![allow(unused)]
fn main() {
rsx! {
    div { style: "
        --rinch-primary-color: #ff6b6b;
        --rinch-radius-default: 0px;
    ",
        // Red primary, sharp corners — only inside this div
        Button { "I'm red and sharp" }
        TextInput { placeholder: "Me too" }
    }
}
}

This is how you create themed sections, cards with different accent colors, or “danger zone” areas with red buttons — without changing the global theme.

Replacing the Theme Entirely

The theme is just CSS. If you hate it, replace it:

#![allow(unused)]
fn main() {
use rinch::theme::{Theme, ColorName};

let theme = Theme::builder()
    .primary_color(ColorName::Cyan)
    .dark_mode(true)
    .build();

// Generate the CSS string and do whatever you want with it
let css = rinch_theme::generate_theme_css(&theme);
}

Or ignore the theme system entirely and write your own CSS variables, your own classes, your own inline styles. Rinch components read from --rinch-* variables. If those variables exist, components use them. If they don’t, components fall back to hardcoded defaults. You’re never locked in.

Dark Mode

#![allow(unused)]
fn main() {
let theme = ThemeProviderProps {
    dark_mode: true,
    ..Default::default()
};
}

In dark mode, semantic colors flip:

  • --rinch-color-body becomes dark gray
  • --rinch-color-text becomes light
  • Component backgrounds, borders, and hover states all adjust

For dynamic dark mode toggling (e.g., a switch in your app), use dark_mode_fn on WASM or re-create the theme and call update_theme() on desktop.

Color Palette Reference

ColorShade 0 (lightest)Shade 6 (primary)Notes
dark#C1C2C5#1A1B1EDark grays
gray#f8f9fa#868e96gray-0 = default body background
red#fff5f5#fa5252
pink#fff0f6#e64980
grape#f8f0fc#be4bdb
violet#f3f0ff#7950f2
indigo#edf2ff#4c6ef5
blue#e7f5ff#228be6Default primary
cyan#e3fafc#15aabf
teal#e6fcf5#12b886
green#ebfbee#40c057
lime#f4fce3#82c91e
yellow#fff9db#fab005
orange#fff4e6#fd7e14

Gotcha: --rinch-color-gray-0 is #f8f9fa, which matches the default body background. If you use it as a card background, it’ll be invisible. Use gray-1 or higher for visible backgrounds.