Get started
Theming
Dark mode, palettes and materials: change the look without forking a component.
Dark mode
Bevel follows the shadcn convention: a .dark class on html. In the dark, the light dims rather than inverting. Highlights get weaker, and paper stays paper, just less lit. With next-themes, set attribute="class" and it works.
For a theme switch that feels like the lights going down, the theme-transition item runs the change through a View Transition:
npx shadcn@latest add @bevel/theme-transitionimport { transitionTheme } from "@/lib/theme-transition"
onClick={() => transitionTheme(next, () => setTheme(next))}Change a palette
Each component names its colours once, as variables in its stylesheet. Override them in your own CSS, globally or under any selector, and the component follows. Nothing to fork.
/* Brand red for every alarm lamp */
:root {
--annunciator-red: oklch(0.6 0.22 15);
}
/* A green-steel Kardex tray, only in the billing area */
.billing [data-slot="visible-file"] {
--visible-file-tray: oklch(0.5 0.04 160);
}Change the whole look
Foundation tokens change everything at once. A flatter, softer set needs only a few lines:
:root {
--bevel-shade: oklch(0 0 0 / 0.2); /* softer shadows */
--bevel-radius-md: 0.875rem; /* rounder objects */
--bevel-duration-move: 240ms; /* snappier motion */
}One-off changes
Every part accepts className, merged last, so yours wins. Parts carry data-slot and their state as data-* attributes, so you can style any part in any state from outside:
<AnnunciatorTile className="min-h-20 text-sm" ... />[data-slot="annunciator-tile"][data-state="new"] {
outline: 2px solid var(--annunciator-red);
}render prop, where a part supports it. There is no asChild.