P PasteCode
Rule

Cursor Rules for Tailwind CSS and shadcn/ui

Cursor rules that enforce Tailwind v4 conventions and shadcn/ui component patterns, preventing agents from reinventing primitives that already exist.

Cursor Next.jsTypeScriptTailwind
.md .json Updated Jun 8, 2026

Paste this into .cursor/rules/tailwind-shadcn.mdc (or your project-level Cursor rules file). Cursor loads all .mdc files in .cursor/rules/ automatically on project open.

Cursor Rules File

Cursor Rules
# Tailwind CSS + shadcn/ui Rules
## Tailwind conventions
- Use Tailwind CSS v4. Class names follow the v4 API — do NOT use deprecated v3
class names (e.g. use `shadow-sm` not `drop-shadow-sm` for box shadows on elements).
- All utility classes must be static strings so Tailwind's content scanner can detect
them. Never build class names with string concatenation or template literals unless
the full class name is in the source (e.g. `bg-${color}` is forbidden; use a lookup
object instead).
- Class order: layout → box model → typography → visual (bg, border, shadow) →
interactive (hover, focus) → responsive breakpoints. Use `prettier-plugin-tailwindcss`
to enforce this automatically — do not manually reorder.
- Never write custom CSS for spacing, color, or typography that can be expressed with a
Tailwind utility. Custom CSS lives in `src/styles/` and must be justified by a comment.
- Use `cn()` from `@/lib/utils` to merge conditional classes. Never use `clsx` or
`classnames` directly elsewhere — they are already re-exported from `cn()`.
## shadcn/ui conventions
- Before creating a new UI component, check `src/components/ui/` for an existing
shadcn/ui primitive. Use it. Do not re-implement Button, Dialog, Input, Select,
Tooltip, or any other component that shadcn already provides.
- Add new shadcn components with `npx shadcn@latest add <component>` — never copy-paste
component source manually from the docs.
- Extend shadcn components by wrapping them, not by editing the file in
`src/components/ui/` directly. Edits there are overwritten by future `shadcn add` runs.
- Use shadcn's `variant` and `size` props before adding className overrides. If a new
variant is needed, add it to the component's `cva()` definition in `src/components/ui/`.
- Dark mode is handled by the `dark` class on `<html>`. Never use `prefers-color-scheme`
media queries alongside shadcn — they conflict with the class strategy.
- Do not install `@radix-ui/*` packages directly. They are transitive dependencies of
shadcn components; adding them directly risks version mismatches.
## Accessibility
- Every interactive shadcn component must have an accessible label. Use `aria-label`,
`aria-labelledby`, or a visually-hidden `<span>` — never omit it.
- Icon-only buttons must include `<span className="sr-only">Description</span>`.
## Definition of done
- `bun run build` completes without Tailwind class warnings.
- No `className` strings contain dynamic concatenation (`bg-` + variable).
- No new Radix packages in `package.json` that aren't installed via `shadcn add`.
- Storybook (if present) renders the new/modified component without console errors.

Why these rules

  • “Check src/components/ui/ before creating anything” is the single highest-value rule for shadcn projects. Agents default to writing bespoke components — a custom <Button>, a hand-rolled <Select> — that duplicate the shadcn primitives already in the repo. This wastes tokens, creates inconsistency, and bypasses accessibility work shadcn ships for free.
  • Static class name strings is a hard constraint from Tailwind’s scanner. Agents routinely produce bg-${color}-500 style interpolation that compiles but produces no CSS at runtime, causing invisible styling bugs that only appear in production builds.

Good fit

  • Next.js or Astro projects already using shadcn/ui with Tailwind v4, where the primary risk is agents duplicating existing primitives or fighting the design system.

Not a fit

  • Projects using CSS Modules, Emotion, or Styled Components — Tailwind class-order rules are irrelevant and cn() does not exist.