Tailwind
A Tailwind codebase degrades one arbitrary value at a time. Every value you hardcode is a design
decision the theme can no longer make.
When this fires
Writing or editing Tailwind utility classes in a project that already uses Tailwind. It does not
fire for choosing a styling approach, for visual design direction, or for CSS in a project that
does not use Tailwind.
Procedure
- Read the theme before writing a class. Tailwind's major versions place theme configuration
differently — a JS/TS config file in some, a CSS-side theme block in others — so find where
this project defines its tokens (and confirm the version from the lockfile; see
stack-detection). Read the colors, spacing, radius, font and breakpoint tokens that exist.
- Read one or two existing components in the same area. The class vocabulary a team actually
uses is a stronger constraint than what Tailwind permits.
- Reach for a token before a value. Semantic color tokens over raw palette steps, scale
spacing over pixel values. If you are about to type a bracketed arbitrary value, first check
whether a token covers it.
- When no token covers it, add the token — do not sprinkle the value. Ask whether this is a
one-off (one arbitrary value, with a comment saying why) or a design decision (belongs in the
theme). Adding a theme token changes the whole app's vocabulary, so say what you are adding and
why in the report.
- Do not extract on the second repetition. Two similar class lists are cheaper than a wrong
abstraction. At the third, extract a component — the props and boundaries question is
component-architecture, not a CSS question. Reserve @apply for a genuinely global primitive
in the stylesheet; an @apply block that reimplements a component is worse than the repetition.
- Merge conditional classes with the project's helper. Later position in the
class string
does not win a conflict — the generated stylesheet's order decides, so p-2 and p-4 in
one string resolve unpredictably. Use the project's existing cn/merge utility for any
conditional or overridable class, and pass overrides through it rather than concatenating.
- Never build a class name from a fragment. Tailwind finds classes by scanning source text,
so
bg-${color}-500 produces no CSS. Write full class strings in a lookup map, and confirm the
file you are editing is inside the project's content/source scan paths — a class in an
unscanned file silently produces nothing.
- Make dark mode a token decision, not a per-utility one. Check the project's dark-mode
strategy first (media query vs a class/attribute toggle) and follow it. Prefer semantic tokens
whose values differ per theme over stacking a
dark: variant on every utility; add dark:
where the token system genuinely cannot express the difference.
- Keep the class order the project keeps. If a class-sorting formatter is configured, run the
project's format command rather than hand-sorting.
- Look at it in both themes and at the breakpoints you touched. Class lists are not evidence
of rendering; hand that off to
browser-verification.
Checklist
Failure handling
- A class is in the source but no style appears — check, in order: the file is inside the scan
paths, the class name is a complete literal string, the utility actually exists in this major
version, and the build was re-run.
- A style applies but the wrong value wins — a conflict, not a specificity puzzle. Route both
classes through the merge helper instead of adding
!important.
- Dark mode is right in one place and wrong in another — the two places are using different
mechanisms (one token, one
dark: variant). Unify on the project's strategy.
- A design needs a value no token has and the theme owner is not you — use one arbitrary value
with a comment and raise the missing token. Do not add tokens to a shared theme unasked; that is
a change to every screen.
- A theme token's value needs changing — that repaints the app. Stop and ask before editing an
existing token's value, even when it looks obviously wrong.
Evidence to report
The tokens used; any token added, with its file and the reason; the count of arbitrary values left
and why each survived; whether repetition was extracted or deliberately left; and confirmation that
light and dark were both rendered, or a plain statement that they were not.
1---2name: tailwind3description: Work inside an existing Tailwind codebase without degrading it — use the project's theme tokens instead of arbitrary values, extend the theme when a token is genuinely missing, extract repetition into components rather than @apply, resolve class conflicts with the project's merge helper, and make dark mode a token decision. Fires when writing or editing Tailwind classes in a repo that already uses it. Not for deciding whether to adopt Tailwind, not for visual design direction, and not a rendered-output check.4---56# Tailwind78A Tailwind codebase degrades one arbitrary value at a time. Every value you hardcode is a design9decision the theme can no longer make.1011## When this fires1213Writing or editing Tailwind utility classes in a project that already uses Tailwind. It does not14fire for choosing a styling approach, for visual design direction, or for CSS in a project that15does not use Tailwind.1617## Procedure18191. **Read the theme before writing a class.** Tailwind's major versions place theme configuration20 differently — a JS/TS config file in some, a CSS-side theme block in others — so find where21 *this* project defines its tokens (and confirm the version from the lockfile; see22 `stack-detection`). Read the colors, spacing, radius, font and breakpoint tokens that exist.232. **Read one or two existing components** in the same area. The class vocabulary a team actually24 uses is a stronger constraint than what Tailwind permits.253. **Reach for a token before a value.** Semantic color tokens over raw palette steps, scale26 spacing over pixel values. If you are about to type a bracketed arbitrary value, first check27 whether a token covers it.284. **When no token covers it, add the token — do not sprinkle the value.** Ask whether this is a29 one-off (one arbitrary value, with a comment saying why) or a design decision (belongs in the30 theme). Adding a theme token changes the whole app's vocabulary, so say what you are adding and31 why in the report.325. **Do not extract on the second repetition.** Two similar class lists are cheaper than a wrong33 abstraction. At the third, extract a **component** — the props and boundaries question is34 `component-architecture`, not a CSS question. Reserve `@apply` for a genuinely global primitive35 in the stylesheet; an `@apply` block that reimplements a component is worse than the repetition.366. **Merge conditional classes with the project's helper.** Later position in the `class` string37 does **not** win a conflict — the generated stylesheet's order decides, so `p-2` and `p-4` in38 one string resolve unpredictably. Use the project's existing `cn`/merge utility for any39 conditional or overridable class, and pass overrides through it rather than concatenating.407. **Never build a class name from a fragment.** Tailwind finds classes by scanning source text,41 so `bg-${color}-500` produces no CSS. Write full class strings in a lookup map, and confirm the42 file you are editing is inside the project's content/source scan paths — a class in an43 unscanned file silently produces nothing.448. **Make dark mode a token decision, not a per-utility one.** Check the project's dark-mode45 strategy first (media query vs a class/attribute toggle) and follow it. Prefer semantic tokens46 whose values differ per theme over stacking a `dark:` variant on every utility; add `dark:`47 where the token system genuinely cannot express the difference.489. **Keep the class order the project keeps.** If a class-sorting formatter is configured, run the49 project's format command rather than hand-sorting.5010. **Look at it in both themes and at the breakpoints you touched.** Class lists are not evidence51 of rendering; hand that off to `browser-verification`.5253## Checklist5455- [ ] Theme tokens read before classes were written56- [ ] No arbitrary value that an existing token covers57- [ ] Any new token added to the theme, with the reason stated58- [ ] Repetition extracted at the third occurrence, as a component59- [ ] `@apply` used only for a global primitive, if at all60- [ ] Conditional/override classes routed through the project's merge helper61- [ ] No class name assembled from fragments62- [ ] Dark mode expressed through tokens where the system allows it63- [ ] Project formatter run; class order matches the codebase64- [ ] Light and dark rendered and looked at, not inferred6566## Failure handling6768- **A class is in the source but no style appears** — check, in order: the file is inside the scan69 paths, the class name is a complete literal string, the utility actually exists in this major70 version, and the build was re-run.71- **A style applies but the wrong value wins** — a conflict, not a specificity puzzle. Route both72 classes through the merge helper instead of adding `!important`.73- **Dark mode is right in one place and wrong in another** — the two places are using different74 mechanisms (one token, one `dark:` variant). Unify on the project's strategy.75- **A design needs a value no token has and the theme owner is not you** — use one arbitrary value76 with a comment and raise the missing token. Do not add tokens to a shared theme unasked; that is77 a change to every screen.78- **A theme token's value needs changing** — that repaints the app. Stop and ask before editing an79 existing token's value, even when it looks obviously wrong.8081## Evidence to report8283The tokens used; any token added, with its file and the reason; the count of arbitrary values left84and why each survived; whether repetition was extracted or deliberately left; and confirmation that85light and dark were both rendered, or a plain statement that they were not.