Using components
Components are source files in your project, not a package you update. This page covers how to use them and how to style the code around them so it matches.
Import a component
After npx werewolf-ui add card button field input, the files sit under your UI alias, by default @/components/ui. Import them like any other file in your app.
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { Field, FieldControl, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
export function ProjectCard() {
return (
<Card>
<CardHeader>
<CardTitle>Project</CardTitle>
<CardDescription>Last edited 2 hours ago.</CardDescription>
</CardHeader>
<CardContent>
<Field>
<FieldLabel>Name</FieldLabel>
<FieldControl>
<Input placeholder="My project" />
</FieldControl>
</Field>
</CardContent>
<CardFooter>
<Button variant="secondary">Cancel</Button>
<Button>Save</Button>
</CardFooter>
</Card>
)
}The code is yours
Change a component file when you need to. Running add again skips identical files and reports a conflict for any file that differs, so your change is never lost. To take the new version, review the difference, then pass that exact path to --overwrite.
npx werewolf-ui add button --overwrite src/components/ui/button.tsxPick one size per region
Controls take size: sm, md (the default), lg or xl. Choose the size for a region, not per control, and never put two neighboring sizes in one row. On touch screens md, lg and xl grow on their own, so do not change sizes at a breakpoint.
| Size | Mouse | Touch | Use for |
|---|---|---|---|
sm | 28px | 28px, 44px hit area | Toolbars, tables, dense menus |
md | 32px | 36px | Everywhere by default |
lg | 36px | 44px | Roomy forms and settings |
xl | 44px | 48px | The primary action, touch-first screens |
<div className="flex gap-sm">
<Button size="sm" variant="ghost">Filter</Button>
<Button size="sm" variant="ghost">Sort</Button>
</div>
<Button size="xl" fullWidth>Continue</Button>Style with token classes
For your own layout, use the Tailwind classes that the token stylesheet adds. A color class is the utility plus the token name without color-: bg-background-surface, text-text-secondary, border-border. Spacing is p-md, gap-sm, mt-xs; corners are rounded-element and rounded-container; type is text-sm or text-heading-3.
<section className="rounded-container border border-border bg-background-surface p-lg">
<h2 className="text-heading-3 text-text-primary">Billing</h2>
<p className="mt-xs text-sm text-text-secondary">Your plan renews on May 1.</p>
</section>Tailwind's own palette, radius, shadow and font weight scales are cleared, so palette classes (a hue with a number), rounded-lg and font-bold produce no CSS. Never hardcode a color, as a hex value or a color function. If no token fits, report it instead of inventing one. The Tokens page lists every name.
Text on colored fills
- On the accent fill, text and icons use only
text-text-on-accentandtext-icon-on-accent. With the default accent,text-text-primaryonbg-accentis invisible in dark mode. - Badges, tags and banners use a soft fill with its matching text:
bg-background-green text-text-green. - Hover and pressed states are overlays on the normal fill (
hover:overlay-hover active:overlay-pressedwithtransition-control), not new colors. - Make text quieter with
text-text-secondaryortext-text-tertiary, never with opacity.
Dark and light mode
Dark is the default. Set data-theme="light" on <html> for a light page, or on any element for one region. Tokens switch on their own, so never write dark: variants.
<html lang="en" data-theme="light">
<div data-theme="dark">Always dark, even on a light page.</div>Add classes to a component
Every component accepts className. The utils item that add installs provides cn, which merges classes and knows the token class names, so your class wins over the component's default.
import { cn } from "@/lib/utils"
<Button className={cn("w-full", isPrimary && "shadow-med")}>Save</Button>Loading states
Never blank content while the next content loads. Keep it on screen with the pending prop (Table, TabsContent), which dims it and marks it busy. Use a Skeleton only for a first load, shaped like the content, through useSkeletonDelay so it shows after about 150ms and for at least 300ms.
Icons
Components and docs use Tabler Icons, but any icon set works. Always pass a size: 16px in sm, md and lg controls, 20px in xl controls and navigation. See Iconography.
Check your code
Run lint after you or your agent change UI. It flags hardcoded colors, cleared Tailwind classes, dark: variants, unknown tokens and arbitrary spacing, and --fix applies the edits it can prove.
npx werewolf-ui lint src --fix