Theming
Bloom's entire visual system is built on CSS custom properties. To customize any aspect of the design — colors, typography, spacing, radii, shadows, or motion — you override these properties in your own CSS.
How it works
All Bloom components read their values from CSS variables defined on :root. Override any subset of them in your stylesheet and every component updates automatically:
:root {
--bloom-bg: #faf6f1;
--bloom-accent1: #5a7a5a;
--bloom-radius: 14px;
}No re-compilation needed. Changes take effect immediately in the browser.
Token reference
| Token | What it controls |
|---|---|
--bloom-font | Body font family |
--bloom-font-display | Heading/display font family |
--bloom-bg | Page background |
--bloom-surface | Card, input, toast backgrounds |
--bloom-surface2 | Borders, dividers, hover states |
--bloom-text | Primary text color |
--bloom-text-secondary | Labels, descriptions, captions |
--bloom-accent1 / --bloom-accent1-deep | Primary/success color (sage) |
--bloom-accent2 / --bloom-accent2-deep | Warning color (sand) |
--bloom-accent3 / --bloom-accent3-deep | Info/accent color (lavender) |
--bloom-accent4 / --bloom-accent4-deep | Danger/error color (rose) |
--bloom-shadow / --bloom-shadow-hover | Elevation shadows |
--bloom-radius-sm / --bloom-radius / --bloom-radius-lg / --bloom-radius-pill | Border radius scale |
--bloom-duration / --bloom-duration-slow / --bloom-duration-fast | Animation timing |
--bloom-ease | Easing curve |
--space-xs through --space-4xl | Spacing scale |
Palette system
Instead of overriding individual tokens, you can switch between named palettes using ThemeProvider. A palette sets a coherent group of color tokens in one go.
Built-in palettes
Bloom ships several palettes out of the box:
import { ThemeProvider, builtInPalettes } from "@bloomkit/react";
export default function App({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider palettes={builtInPalettes} defaultPalette="bloom">
{children}
</ThemeProvider>
);
}Switching palettes at runtime
Use the setPalette function from the useTheme hook to switch palettes programmatically:
import { useTheme } from "@bloomkit/react";
export function PaletteSwitcher() {
const { palette, setPalette, palettes } = useTheme();
return (
<div>
{palettes.map((name) => (
<button
key={name}
onClick={() => setPalette(name)}
aria-pressed={palette === name}
>
{name}
</button>
))}
</div>
);
}Defining a custom palette
Pass your own palette definitions to ThemeProvider alongside (or instead of) the built-ins:
import { ThemeProvider, builtInPalettes } from "@bloomkit/react";
import type { Palette } from "@bloomkit/react";
const myPalette: Palette = {
name: "forest",
tokens: {
"--bloom-bg": "#f2f5f0",
"--bloom-surface": "#e8ede5",
"--bloom-surface2": "#cdd7c8",
"--bloom-text": "#1e2b1c",
"--bloom-text-secondary": "#4a6047",
"--bloom-accent1": "#3d6b3a",
"--bloom-accent1-deep": "#2a4c28",
},
};
export default function App({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider palettes={[...builtInPalettes, myPalette]} defaultPalette="forest">
{children}
</ThemeProvider>
);
}Only the tokens you specify are overridden — any token you omit falls back to Bloom's defaults.