theming
Three orthogonal axes — color scheme, accent, and design language — driven by CSS attributes.
Fluixi UI themes through three independent attributes on any element (usually
<html>), so they compose freely — dark + violet + Material all at once:
| Axis | Attribute | Values |
|---|---|---|
| Color scheme | data-theme |
light · dark · high-contrast |
| Accent | data-accent |
blue (default) · violet · rose · green |
| Design language | data-ui |
fluixi (default) · material |
Every component reads semantic CSS variables (--flx-ui-color-primary, …), so
changing an attribute re-themes the whole tree with no per-component work.
Setup
Inject the token variables once, and import the default skin:
import { injectTokens } from '@fluixi-ui/tokens/theme';
import '@fluixi-ui/tokens/preset.css';
injectTokens();
Driving the axes
Each axis is just an attribute. Drive them reactively with createTheme from
@fluixi/core — one store per axis. It detects, persists, applies, follows
system preference, and ships a no-flash head script.
import { createTheme } from '@fluixi/core';
const scheme = createTheme({
attribute: 'data-theme',
themes: ['light', 'dark', 'high-contrast'],
default: 'light',
system: { dark: 'dark', light: 'light' }, // follow prefers-color-scheme
});
const accent = createTheme({ attribute: 'data-accent', themes: ['blue', 'violet', 'rose', 'green'], default: 'blue' });
scheme.init(); // apply on client mount
accent.init();
scheme.toggle(); // cycle through the theme list
accent.set('violet');
@fluixi-ui/tokens also offers a scheme-only createThemeController (light/dark/
high-contrast + system) if you only need the color scheme.
Accent palettes
data-accent swaps only the accent scale — blue is the built-in default;
violet, rose, and green are alternates (Radix violet / crimson / grass).
Every color-primary / focus / selection token derives from the accent, so a
single attribute recolors the whole UI. Add your own by extending the token
stylesheet with a [data-accent='…'] block that overrides --flx-ui-accent-1…12.
Design language (skins)
data-ui switches the visual language. fluixi is the default clean skin;
@fluixi-ui/skin-material is a Material Design skin. Load a
skin's CSS only when it's active with createTheme's load hook:
const skin = createTheme({
attribute: 'data-ui',
themes: ['fluixi', 'material'],
default: 'fluixi',
load: (s) => s === 'material' && import('@fluixi-ui/skin-material/styles.css'),
});
skin.init();
No-flash SSR
When server-rendering, drop the head script so the attribute is set before first paint (no theme flash before hydration):
<head>{/* … */}
<script innerHTML={scheme.headScript()} />
</head>
Scoped theming
The attributes work on any element, not just the root — so a subtree can carry its own scheme or accent. The semantic layer is re-emitted in every scope, so nested regions re-resolve correctly:
<section data-theme="dark" data-accent="rose">
<!-- dark + rose here, regardless of the page theme -->
</section>
Overriding tokens
The token variables and the default skin live in CSS @layers
(flx.tokens, flx.components, flx.skin, in that order). Your CSS stays
unlayered, so it always wins — override a token anywhere:
:root { --flx-ui-color-primary: #7c3aed; }
Part of the Fluixi UI component library. Made with ☕ by the Fluixi team.