| Situation | Do this | Why |
|---|---|---|
| New reusable design token | @theme { --color-brand: ...; } | Auto-generates the matching utility |
| One-off value, no reusable token needed | bg-[#316ff6] (arbitrary value) | Skips polluting the theme for a single use |
Token value is var(...) referencing another variable | @theme inline { --font-sans: var(--font-inter); } | Plain @theme can resolve to the wrong scope |
| Full-viewport height on mobile | min-h-dvh, not min-h-screen | vh/screen misbehaves under mobile browser chrome |
| Style a component by its own size, not the page | @container + @sm: | Portable across sidebar/main/modal placements |
| Style based on descendant's state | has-checked:, or group+group-has-checked: on an ancestor | No JS state tracking needed |
| Style based on a later sibling's state | mark earlier element peer, target with peer-*: | peer must precede the styled element in the DOM |
| Two utilities would target the same CSS property | Branch the class string, never apply both | Cascade order (not class order) decides the winner |
| Multi-line truncation | line-clamp-<n> | No JS, no manual height + overflow hack |
| Single-line truncation | truncate | Shorthand for overflow-hidden text-overflow-ellipsis whitespace-nowrap |
| Icon should match surrounding text color | fill-current/stroke-current | Recolors via the parent's text-*, not per-icon overrides |
| Frosted-glass panel | backdrop-blur-* + a translucent bg-*/<opacity> | backdrop-filter needs transparency to be visible |
| Shadow on a transparent PNG/icon | drop-shadow-*, not box-shadow | Follows the alpha shape, not the bounding box |
| Disable Preflight for legacy integration | Import theme.css+utilities.css, skip preflight.css | Documented, supported integration path |
| Migrating v3 → v4 | npx @tailwindcss/upgrade, review diff | Handles most mechanical renames automatically |
| Prefix | Min-width | Prefix | Min-width | |
|---|---|---|---|---|
sm: | 640px | @3xs | 256px | |
md: | 768px | @xs | 320px | |
lg: | 1024px | @sm | 384px | |
xl: | 1280px | @md | 448px | |
2xl: | 1536px | @lg…@7xl | 512px…1280px |
max-{bp}: applies below that breakpoint; stack {bp}:max-{bp2}: for a range. Same pattern with @ for container queries.
| Suffix | Resolves to |
|---|---|
-<number> | calc(var(--spacing) * <number>) |
-<fraction> | calc(<fraction> * 100%) |
-px | 1px |
-full | 100% |
-auto | auto (margin/width/height only, not padding/max-*) |
-(<custom-property>) | var(<custom-property>) |
-[<value>] | literal arbitrary value |
Default --spacing = 0.25rem — p-4 = 1rem = 16px.
| Prefix | Meaning |
|---|---|
hover: focus: active: | Interaction pseudo-classes |
disabled: invalid: checked: | Form-state pseudo-classes |
first: last: odd: even: nth-<n>: | Structural position |
has-*: | Based on own descendants |
group-*: / peer-*: | Based on a marked ancestor / earlier sibling |
not-*: | Negates any other variant |
dark: | prefers-color-scheme: dark (overridable) |
motion-reduce: motion-safe: | prefers-reduced-motion |
aria-*: data-*: | Attribute-based (headless UI state) |
rtl: ltr: | Text direction |
starting: | @starting-style (entry transitions) |
supports-[...]: | @supports feature query |
*: / **: | Direct children / all descendants |
| v3 | v4 |
|---|---|
shadow-sm/shadow | shadow-xs/shadow-sm |
blur-sm/blur | blur-xs/blur-sm |
rounded-sm/rounded | rounded-xs/rounded-sm |
outline-none | outline-hidden (new outline-none really means outline-style:none) |
ring (3px, blue-500) | ring-3 + explicit ring-<color> (1px, currentColor default) |
@tailwind base/components/utilities | @import "tailwindcss"; |
Leading !util important | Trailing util! |
bg-[--var] | bg-(--var) |