Recommended stack
A design kit controls the look. The stack underneath controls whether that look actually holds across the entire product. These recommendations come from shipping agent-built projects where the kit stayed consistent across hundreds of components.
Component primitives
Every interactive element (button, input, select, dialog, tooltip, popover, tabs, accordion) should use a component primitive library, not raw HTML. The kit handles the visual layer; the primitive handles behavior, accessibility, keyboard navigation, and screen reader announcements.
| Library | When to use it |
|---|---|
| shadcn/ui | Default choice. Components copy into your project as source code using CSS variables. Identity Forge ships a shadcn registry that installs a kit's tokens in one command. |
| Radix UI | When you want full control over markup and styling. The unstyled primitives underneath shadcn. |
| Base UI | Alternative unstyled primitives with a minimal API. shadcn/ui also ships a Base UI registry. |
Pick one and stay with it. Mixing primitive libraries in the same project creates inconsistency in focus behavior, portal placement, and animation timing.
Hard requirements
Add these to your project instructions (CLAUDE.md, .cursorrules, or equivalent). They are the minimum set that keeps a design kit effective.
Every UI element uses a primitive
## Component rules
Every interactive UI element uses shadcn/ui (or Radix UI / Base UI).
No raw HTML `<button>`, `<input>`, `<select>`, `<dialog>`, or `<table>`.
Custom components wrap the primitive, never replace it.
Components live in src/components/ui/ as source code.
Tokens, not values
## Design tokens
No hex colors, no rgb(), no hsl() literals in components.
All colors via Tailwind classes mapped to CSS custom properties:
bg-primary, text-foreground, border-border, bg-muted, etc.
All radii via the --radius token: rounded-sm, rounded-md, rounded-lg.
Verification: `grep -rn '#[0-9a-fA-F]' src/components/` must return zero hits.
Conditional styling through cn()
## Styling
All conditional class composition through cn() (clsx + tailwind-merge).
No string concatenation for classes. No ternary-in-className without cn().
Pattern: className={cn("base-classes", condition && "conditional-classes", className)}
Review flow
After completing a feature or section, run a review as a separate agent prompt:
Review every component in src/components/ and flag:
1. Any interactive element not using shadcn/ui, Radix, or Base UI
2. Any hardcoded color (grep -rn '#[0-9a-fA-F]' src/components/ must return zero)
3. Any className composition that doesn't use cn()
4. Any raw HTML form element (<input>, <select>, <textarea>) not wrapped in a primitive
For each finding: fix it, don't just flag it.
Run this as a separate prompt after the implementation work, not during it. Mixing implementation and review in one prompt produces weaker results in both.
Full stack recommendation
For a new project using Identity Forge design kits:
| Layer | Recommendation |
|---|---|
| Framework | Next.js (App Router) with TypeScript strict |
| Styling | Tailwind CSS with design kit tokens as CSS custom properties |
| Components | shadcn/ui (copies into project, uses CSS variables natively) |
| Forms | React Hook Form + Zod validation |
| Motion | motion/react with semantic duration constants, not magic numbers |
| Internationalization | next-intl (all user-facing text via message catalogs) |
| Design system | Identity Forge kit installed via CLI, MCP, or shadcn registry |
This is not the only stack that works, but it is the one where the most friction has been removed. The shadcn registry install maps kit tokens directly to the CSS variables shadcn components already use, so the kit applies with zero manual wiring.
Enforcement in agent instructions
Copy this block into your project's agent instructions file. It combines the hard requirements above with the review trigger.
## Design system enforcement
This project uses an Identity Forge design kit as the single source of truth
for all visual decisions. The kit tokens are installed as CSS custom properties.
### Rules (no exceptions)
- Every interactive element uses shadcn/ui, Radix UI, or Base UI primitives
- Every color, radius, shadow, and font reference uses a design token
- All conditional class composition uses cn() (clsx + tailwind-merge)
- No raw HTML form elements: <input>, <select>, <textarea>, <button>
### Verification
After completing any UI work, run:
grep -rn '#[0-9a-fA-F]' src/components/
Zero results means the token rule holds. Any hit must be fixed before the work
is considered done.
### Periodic review
After completing a feature, review src/components/ for:
primitives not used, tokens not used, cn() not used, raw HTML form elements.
Fix each finding in place.