brutalkit
v0.4.0
Published
A tokens-first design system built on shadcn/ui
Readme
Brutalkit
A tokens-first design system built on shadcn/ui. Thick borders, hard-edge shadows, OKLCH color tokens, and Phosphor icons.
Install
npm install brutalkitPeer dependencies:
npm install react react-dom @phosphor-icons/react tailwindcssSetup
Import the stylesheet after Tailwind in your app's CSS:
@import "tailwindcss";
@import "brutalkit/styles";That is all that is required. Brutalkit tells Tailwind where to find its own
compiled components, so component utilities are generated automatically — you do
not need to add a @source directive yourself.
Optionally opt in to the global resets, which set the body background and
foreground and the default border color on every element:
@import "brutalkit/preflight";These are not applied by brutalkit/styles, so dropping brutalkit into an
existing app does not change that app's baseline.
Add fonts (or use your own):
@import "@fontsource-variable/fraunces/opsz.css";
@import "@fontsource/geist-sans";
@import "@fontsource/jetbrains-mono";Set a theme on your root element:
<html data-theme="sage">The theme attribute must live on <html> (or be applied via ThemeProvider,
which does this for you). Components like Dialog, Select, and Tooltip
portal their content to document.body, so a theme scoped to a nested wrapper
leaves that portalled content with no tokens — panels render transparent.
Themes
Five theme families, each with light and dark modes. All share the same ochre --brand;
each family sets its own neutral --accent for hover and highlight surfaces.
| Theme | Vibe | Radius |
|-------|------|--------|
| sage | Clean stone neutral | 4px |
| frost | Cool blue-gray | 4px |
| ink | Max contrast black/white | 4px |
| paper | Restrained warm | 4px |
| midnight | Deep indigo | 12px |
Toggle dark mode by adding the dark class:
<html data-theme="frost" class="dark">ThemeProvider
Use the built-in provider for runtime switching:
import { ThemeProvider } from "brutalkit";
function App() {
return (
<ThemeProvider defaultFamily="sage" defaultMode="system">
{/* ... */}
</ThemeProvider>
);
}import { useTheme } from "brutalkit";
function ThemeSwitcher() {
const { family, setFamily, mode, setMode } = useTheme();
// ...
}Usage
Components use deep imports — no barrel file:
import { Button } from "brutalkit/button";
import { Card, CardHeader, CardTitle, CardContent } from "brutalkit/card";
import { Input } from "brutalkit/input";Components
80+ components including all shadcn/ui primitives plus:
- Layout: Sidebar, Resizable, ScrollArea, Separator
- Data: Chart, DataTable, Heatmap, JsonViewer, PartitionBar, Table, Timeline
- Feedback: Sonner, Spinner, DotMatrix, StatusIndicator, StatusMonitor, SystemBanner
- Forms: Combobox, DatePicker, MultiSelect, InputGroup, InputOTP, NativeSelect, Field, Slider, Switch
- Media: Carousel, VideoPlayer, Marquee, SpinningCircularText
- Actions: Button, ButtonGroup, CopyButton, SlideToUnlock, Toggle, ToggleGroup
- Overlay: Dialog, Drawer, Sheet, AlertDialog, ContextMenu, DropdownMenu, HoverCard, Popover, Tooltip
- Display: Avatar, Badge, Card, Kbd, Marker, Bubble, TransportBadge, FlipClock, Empty
Browse them all in the Storybook.
Styling
- All colors use semantic tokens (
bg-primary,bg-muted,text-foreground) backed by OKLCH CSS variables --brandis the ochre and is identical in every theme and mode — use it for CTAs and branded active states.--accentis a subtle per-theme neutral for hover and highlight surfaces, not a brand color- Interactive surfaces use
border-2by default - Hover lift (
shadow-brutal+ translate) on primary action buttons only - Custom shadows registered as Tailwind theme tokens:
shadow-brutal,shadow-brutal-lg
Individual theme imports
If you only need specific themes:
@import "brutalkit/themes/sage";
@import "brutalkit/themes/frost";Development
pnpm storybook # component workbench on :6006
pnpm test # vitest + storybook; a11y violations fail the run
pnpm check:stories # every component has a story with real coverage
pnpm audit:visual # contrast / overflow / focus audit, 5 themes x 2 modes
pnpm verify:consumer # proves a fresh install produces styled componentsverify:consumer builds a throwaway app against the packed library and fails if
the shipped stylesheet stops generating component utilities. Run it before
publishing.
License
MIT
