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.