Dark Mode
Bloom ships full dark mode support out of the box. Color mode is managed by ThemeProvider and exposed through the useTheme hook.
Basic setup
Wrap your app with ThemeProvider and set a defaultColorMode. The "system" value automatically follows the user's OS preference:
import { ThemeProvider } from "@bloomkit/react";
export default function App({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider defaultColorMode="system">
{children}
</ThemeProvider>
);
}Other valid values are "light" and "dark" if you want to start in a specific mode.
useTheme hook
The useTheme hook gives you full control over the active color mode and palette from any component:
| Property | Type | Description |
|---|---|---|
colorMode | "light" | "dark" | "system" | The current user-facing setting |
resolvedMode | "light" | "dark" | The actual applied mode (never "system") |
setColorMode | (mode) => void | Explicitly set the color mode |
toggleColorMode | () => void | Toggle between light and dark |
palette | string | The name of the currently active palette |
setPalette | (name) => void | Switch to a different palette by name |
palettes | string[] | All available palette names |
Building a theme toggle
Use toggleColorMode and resolvedMode to build a simple toggle button:
import { useTheme } from "@bloomkit/react";
export function ThemeToggle() {
const { resolvedMode, toggleColorMode } = useTheme();
return (
<button
onClick={toggleColorMode}
aria-label={resolvedMode === "dark" ? "Switch to light mode" : "Switch to dark mode"}
>
{resolvedMode === "dark" ? "Light mode" : "Dark mode"}
</button>
);
}If you need a three-way picker (light / dark / system), use colorMode and setColorMode instead:
import { useTheme } from "@bloomkit/react";
const modes = ["light", "dark", "system"] as const;
export function ColorModePicker() {
const { colorMode, setColorMode } = useTheme();
return (
<div role="group" aria-label="Color mode">
{modes.map((mode) => (
<button
key={mode}
onClick={() => setColorMode(mode)}
aria-pressed={colorMode === mode}
>
{mode}
</button>
))}
</div>
);
}OS preference detection
When defaultColorMode is set to "system", Bloom listens to the prefers-color-scheme media query and applies light or dark tokens automatically. No additional setup is required — this works out of the box.
resolvedMode always reflects the actual applied value, so you can safely use it to render icons or labels without worrying about "system" appearing as a value.
localStorage persistence
ThemeProvider persists the user's color mode choice to localStorage under the key bloom-color-mode. On the next page load the stored preference is read before the first render, preventing a flash of the wrong theme.
If defaultColorMode="system" and the user has never explicitly picked a mode, no value is written to storage and the OS preference continues to be used.
Manual approach (without ThemeProvider)
If you prefer to manage color mode yourself — or are using Bloom inside a larger app that already has its own theme system — you can apply dark mode manually by adding a dark class or data-theme="dark" attribute to your root element:
<!-- class-based -->
<html class="dark">
<!-- attribute-based -->
<html data-theme="dark">Bloom's stylesheet includes .dark and [data-theme="dark"] selectors that override all color tokens to their dark-mode values. Toggle the class or attribute however you like and Bloom will respond accordingly.