Skip to content

Theming

FluxUI is styled entirely via CSS custom properties (design tokens). Switching between light and dark mode — or creating a custom palette — requires no JavaScript and works at runtime without a page reload.


Dark Mode

Call session.set_theme("dark") to switch the current user's session to dark mode. This sends a set_theme message over the WebSocket; the browser adds/removes the data-theme="dark" attribute on <html>.

import fluxui as ui

app = ui.App("Themed App")

@app.page("/")
def home(session):
    dark = ui.state(False)

    async def toggle(v: bool) -> None:
        dark.set(v)
        await session.set_theme("dark" if v else "light")

    with ui.Row(justify="flex-end"):
        ui.Switch("Dark mode", checked=dark, on_change=toggle)

    ui.Heading("Hello, themes!", level=1)

app.run(port=8000)

CSS Design Tokens

All FluxUI components reference these custom properties. Override them in docs/stylesheets/extra.css (for the docs site) or in your app's static CSS to customise the look globally.

Colours

Token Default (light) Usage
--flux-bg #ffffff Page background
--flux-surface #f7f8fa Card and panel background
--flux-border #e1e4e8 Borders and dividers
--flux-text #1a1d23 Primary text
--flux-text-muted #6b7280 Secondary / muted text
--flux-accent #d4a44a Accent colour (buttons, links, focus rings)
--flux-accent-hover #e0b25c Accent hover state
--flux-danger #c0625a Danger / error
--flux-success #5f8a5f Success / positive
--flux-warning #b08544 Warning
--flux-info #4a7fb0 Informational

Spacing

FluxUI uses an 8-point spacing scale:

Token Value
--s-1 4px
--s-2 8px
--s-3 12px
--s-4 16px
--s-5 20px
--s-6 24px
--s-8 32px
--s-10 40px
--s-12 48px

Typography

Token Default Usage
--flux-font Inter, system-ui, sans-serif Body font
--flux-font-mono JetBrains Mono, monospace Code font
--flux-text-sm 0.875rem Small text
--flux-text-base 1rem Base text
--flux-text-lg 1.125rem Large text
--flux-text-xl 1.25rem Extra large
--flux-radius 6px Default border radius
--flux-radius-lg 10px Large border radius
--flux-shadow 0 1px 3px rgba(0,0,0,0.08) Card shadow
--flux-shadow-lg 0 4px 16px rgba(0,0,0,0.12) Modal shadow

Dark Mode Token Overrides

When data-theme="dark" is set on <html>, these overrides apply automatically:

[data-theme="dark"] {
    --flux-bg:           #0d1117;
    --flux-surface:      #161b22;
    --flux-border:       #30363d;
    --flux-text:         #e6edf3;
    --flux-text-muted:   #8b949e;
    --flux-shadow:       0 1px 3px rgba(0,0,0,0.4);
    --flux-shadow-lg:    0 4px 16px rgba(0,0,0,0.5);
}

Per-Component Styling

Every component accepts style= (inline CSS) and class_names= (extra CSS classes):

ui.Card(
    title="Highlighted",
    style={"border": "2px solid var(--flux-accent)", "background": "var(--flux-surface)"},
    class_names=["my-card", "featured"],
)

ui.Button(
    "Custom",
    style={"font-size": "1.2rem", "padding": "1rem 2rem"},
)

ui.theme — ThemeTokens (Planned)

A typed ThemeTokens API is planned for v0.2. It will allow defining palettes as Python dataclasses and passing them to ui.App:

# FUTURE API — not yet available in v0.1
import fluxui as ui

my_theme = ui.theme.light(
    accent="#7c3aed",        # purple accent
    accent_hover="#6d28d9",
)

app = ui.App("Purple App", theme=my_theme)

For now, use CSS custom property overrides directly.