Common tasks
Copy these verbatim. They are the canonical solutions to recurring jobs in the system.
The solid pattern: bg + foreground + border. Never bg-{status}/10.
<Alert variant="destructive">
<XCircleIcon weight="fill" />
<AlertTitle>Couldn't save changes</AlertTitle>
<AlertDescription>Check your network connection.</AlertDescription>
</Alert>Use --color-chart-* in series order. Series 1 anchors to brand lavender.
const palette = Array.from({ length: 12 }, (_, i) => `var(--color-chart-${i + 1})`);
<Bar dataKey="revenue" fill={palette[0]} />
<Bar dataKey="cost" fill={palette[1]} />A consumer project reskin. Drop into the project's globals.css :root.
:root {
--primary: oklch(0.205 0.04 290);
--secondary: oklch(0.86 0.07 50);
--background: oklch(0.99 0.005 80);
--foreground: oklch(0.18 0 0);
--border: oklch(0.92 0.01 80);
--radius-card: 1.25rem;
--radius-button: 0.75rem;
--font-heading: var(--font-inter);
--chart-1: oklch(0.65 0.13 50);
}Toggle [data-density='compact'] on the html element to tighten controls.
<html data-density="compact">…</html>Use --shadow-focus or the canonical --ring-width composition.
className="focus-visible:ring-(length:--ring-width) focus-visible:ring-ring/40 focus-visible:border-ring"text-base on mobile (iOS focus-zoom), helper text, density-aware height.
We'll only use this for login and security alerts.
<div className="flex flex-col gap-(--density-field-gap)">
<Label htmlFor="email">Work email</Label>
<Input id="email" type="email" placeholder="you@company.com" />
<p className="text-xs text-muted-foreground">
We'll only use this for login and security alerts.
</p>
</div>Solid status pattern: bg-destructive/30 helper + border-destructive + aria-invalid.
Enter a valid email address.
<div className="flex flex-col gap-(--density-field-gap)">
<Label htmlFor="email" className="text-destructive">Work email</Label>
<Input
id="email"
type="email"
aria-invalid={true}
aria-describedby="email-error"
className="border-destructive focus-visible:border-destructive focus-visible:ring-destructive/40"
/>
<p id="email-error" className="text-xs text-destructive">
Enter a valid email address.
</p>
</div>Always pair the visible error with aria-invalid + aria-describedby. Color alone is not sufficient for the error to read as an error to assistive tech.
Stack with --density-field-gap. Two-column grids only when fields are short (state, zip).
<form className="flex flex-col gap-(--density-field-gap) max-w-md">
<div className="grid grid-cols-2 gap-3">
<div className="flex flex-col gap-1.5">
<Label htmlFor="first">First name</Label>
<Input id="first" />
</div>
<div className="flex flex-col gap-1.5">
<Label htmlFor="last">Last name</Label>
<Input id="last" />
</div>
</div>
<div className="flex flex-col gap-1.5">
<Label htmlFor="org">Organization</Label>
<Input id="org" />
</div>
<div className="flex justify-end gap-2 pt-2">
<Button variant="ghost" size="sm">Cancel</Button>
<Button size="sm">Save changes</Button>
</div>
</form>Loading state on the submit button only. Don't disable the whole form unless it's destructive.
const [pending, setPending] = useTransition();
<Button type="submit" disabled={pending}>
{pending ? (
<>
<SpinnerIcon className="size-(--size-icon-sm) animate-spin" />
Saving…
</>
) : (
"Save changes"
)}
</Button>Disabled button uses --opacity-disabled automatically via aria-disabled. Don't gray out other fields — the user may still want to edit while the request is in flight.