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

TokenWhat it controls
--bloom-fontBody font family
--bloom-font-displayHeading/display font family
--bloom-bgPage background
--bloom-surfaceCard, input, toast backgrounds
--bloom-surface2Borders, dividers, hover states
--bloom-textPrimary text color
--bloom-text-secondaryLabels, descriptions, captions
--bloom-accent1 / --bloom-accent1-deepPrimary/success color (sage)
--bloom-accent2 / --bloom-accent2-deepWarning color (sand)
--bloom-accent3 / --bloom-accent3-deepInfo/accent color (lavender)
--bloom-accent4 / --bloom-accent4-deepDanger/error color (rose)
--bloom-shadow / --bloom-shadow-hoverElevation shadows
--bloom-radius-sm / --bloom-radius / --bloom-radius-lg / --bloom-radius-pillBorder radius scale
--bloom-duration / --bloom-duration-slow / --bloom-duration-fastAnimation timing
--bloom-easeEasing curve
--space-xs through --space-4xlSpacing 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.