Tailwind Design-System Discipline
Cursor.cursor/rules/*.mdcCoding
Enforces design-token-only Tailwind usage with a fixed class ordering, cn() merging, and a ban on arbitrary values.
Use when: Attach to TSX files in Tailwind v4 projects that define semantic tokens and want every class traceable to the design system.
Get this skill
Add the skill file with the CLI, by hand, or over MCP.Save this to your project or home directory so Cursor can load it.
npx goodprompts add tailwind-design-system-rulesSaves to
./.cursor/rules/tailwind-design-system-rules.mdcnpx goodprompts add tailwind-design-system-rulesSaves to
./.cursor/rules/tailwind-design-system-rules.mdcSkill file
.cursor/rules/*.mdc2,833 characters---
description: Tailwind class conventions — tokens only, ordered classes, cn() merging
globs: "**/*.tsx"
alwaysApply: false
---
# Tailwind rules for this codebase
## Tokens only
- Color classes must reference semantic tokens defined in the theme: `bg-background`, `bg-card`, `text-foreground`, `text-muted-foreground`, `border-border`, `bg-primary text-primary-foreground`, `bg-destructive`. Never use palette colors (`bg-zinc-900`, `text-blue-500`) or hex/rgb values in components.
- Spacing, radius, and shadow come from the scale: `p-4`, `gap-2`, `rounded-md`, `shadow-sm`. If a value isn't on the scale, the design is wrong or the scale needs a token — raise it, don't improvise.
- Dark mode is handled by the tokens themselves. Do not write `dark:` variants for colors; `dark:` is acceptable only for non-color tweaks (e.g. `dark:shadow-none`).
## No arbitrary values
- Square-bracket values are banned: no `w-[417px]`, `text-[13px]`, `bg-[#1a1a2e]`, `mt-[7px]`, `grid-cols-[1fr_2fr]` with magic numbers.
- The only exceptions: CSS-variable passthroughs the system defines (`h-[var(--header-height)]`) and truly content-driven grid templates — and each needs a `// why` comment.
- If you are about to write a bracket, first check: is there a token one step up or down the scale that works? Use it.
## Class ordering
Write classes in this fixed order so diffs stay readable:
1. layout (`flex`, `grid`, `hidden`, `relative`)
2. flex/grid children & alignment (`items-center`, `justify-between`, `gap-2`)
3. sizing (`h-9`, `w-full`, `max-w-md`)
4. spacing (`p-4`, `mx-auto`)
5. typography (`text-sm`, `font-medium`, `tracking-tight`)
6. color & background (`bg-card`, `text-muted-foreground`)
7. borders & radius (`border`, `border-border`, `rounded-lg`)
8. effects (`shadow-sm`, `opacity-50`)
9. transitions & animation (`transition-colors`, `duration-200`)
10. state & responsive variants last (`hover:bg-accent`, `focus-visible:ring-2`, `md:flex-row`)
## Merging with cn()
- Every component that accepts `className` must merge it with `cn()` from `@/lib/utils`, last: `className={cn("flex items-center gap-2", className)}`. Never template-string classes together — `` `${base} ${className}` `` loses Tailwind conflict resolution.
- Conditionals go inside `cn()` as object or `&&` entries: `cn("rounded-md", isActive && "bg-accent")`. No nested ternaries building class strings.
- Variant components use `cva()` with named `variants` and `defaultVariants`; do not branch on a `variant` prop with if/else class assembly.
## Misc
- Prefer `gap-*` over child margins for spacing between siblings. `space-y-*` only for simple text stacks.
- `focus-visible:` (never bare `focus:`) for focus rings, and never remove an outline without replacing it.
- No `@apply` in CSS files except inside the design-system layer itself.