# Tailwind CSS v4 Reference ## Quick Start ```css @import "tailwindcss"; ``` ```html
Hello World
``` --- ## Core Syntax | Pattern | Example | Description | |---------|---------|-------------| | `{utility}` | `flex` | Base utility | | `{variant}:{utility}` | `hover:bg-blue-500` | Conditional application | | `{utility}-{value}` | `p-4`, `text-lg` | Value from scale | | `{utility}-[{value}]` | `p-[13px]`, `grid-cols-[1fr_2fr]` | Arbitrary value | | `{utility}-(--var)` | `p-(--my-spacing)` | CSS variable shorthand | | `{utility}-({type}:--var)` | `text-(color:--my-var)` | Type hint + variable shorthand | | `{utility}-[{type}:{value}]` | `text-[color:var(--my-var)]` | Type hint for arbitrary values | | `{utility}/{opacity}` | `bg-black/50`, `text-white/75` | Opacity modifier | | `-{utility}` | `-mt-4`, `-translate-x-2` | Negative value | | `{utility}!` | `hidden!`, `flex!` | !important modifier | ### Stacking Variants Variants stack left-to-right: `dark:md:hover:bg-blue-500` ### Type Hints When a utility namespace is ambiguous (e.g., `text-*` maps to both `font-size` and `color`), use type hints: - `text-(length:--my-var)` or `text-[length:var(--my-var)]` → `font-size` - `text-(color:--my-var)` or `text-[color:var(--my-var)]` → `color` - `bg-(url:--my-img)` or `bg-[url:var(--my-img)]` → `background-image` --- ## Variants Reference ### Pseudo-classes | Variant | Selector | |---------|----------| | `hover` | `:hover` | | `focus` | `:focus` | | `focus-within` | `:focus-within` | | `focus-visible` | `:focus-visible` | | `active` | `:active` | | `visited` | `:visited` | | `target` | `:target` | | `first` | `:first-child` | | `last` | `:last-child` | | `only` | `:only-child` | | `odd` | `:nth-child(odd)` | | `even` | `:nth-child(even)` | | `first-of-type` | `:first-of-type` | | `last-of-type` | `:last-of-type` | | `only-of-type` | `:only-of-type` | | `nth-{n}` | `:nth-child({n})` | | `nth-last-{n}` | `:nth-last-child({n})` | | `nth-of-type-{n}` | `:nth-of-type({n})` | | `nth-last-of-type-{n}` | `:nth-last-of-type({n})` | | `empty` | `:empty` | | `disabled` | `:disabled` | | `enabled` | `:enabled` | | `checked` | `:checked` | | `indeterminate` | `:indeterminate` | | `default` | `:default` | | `optional` | `:optional` | | `required` | `:required` | | `valid` | `:valid` | | `invalid` | `:invalid` | | `user-valid` | `:user-valid` | | `user-invalid` | `:user-invalid` | | `in-range` | `:in-range` | | `out-of-range` | `:out-of-range` | | `placeholder-shown` | `:placeholder-shown` | | `autofill` | `:autofill` | | `read-only` | `:read-only` | | `has-*` | `:has()` — e.g., `has-[:checked]`, `has-[img]`, `has-checked` | | `not-*` | `:not()` — e.g., `not-hover`, `not-focus`, `not-disabled` | ### Pseudo-elements | Variant | Selector | |---------|----------| | `before` | `::before` (auto adds `content: ''`) | | `after` | `::after` (auto adds `content: ''`) | | `placeholder` | `::placeholder` | | `file` | `::file-selector-button` | | `marker` | `::marker` | | `selection` | `::selection` | | `first-line` | `::first-line` | | `first-letter` | `::first-letter` | | `backdrop` | `::backdrop` | | `details-content` | `::details-content` | ### Media Queries | Variant | Media Query | |---------|-------------| | `sm` | `width >= 40rem` (640px) | | `md` | `width >= 48rem` (768px) | | `lg` | `width >= 64rem` (1024px) | | `xl` | `width >= 80rem` (1280px) | | `2xl` | `width >= 96rem` (1536px) | | `max-sm` | `width < 40rem` | | `max-md` | `width < 48rem` | | `max-lg` | `width < 64rem` | | `max-xl` | `width < 80rem` | | `max-2xl` | `width < 96rem` | | `min-[{value}]` | `width >= {value}` | | `max-[{value}]` | `width < {value}` | | `dark` | `prefers-color-scheme: dark` | | `light` | `prefers-color-scheme: light` | | `motion-safe` | `prefers-reduced-motion: no-preference` | | `motion-reduce` | `prefers-reduced-motion: reduce` | | `contrast-more` | `prefers-contrast: more` | | `contrast-less` | `prefers-contrast: less` | | `forced-colors` | `forced-colors: active` | | `not-forced-colors` | `forced-colors: none` | | `inverted-colors` | `inverted-colors: inverted` | | `portrait` | `orientation: portrait` | | `landscape` | `orientation: landscape` | | `print` | `print` | | `noscript` | `scripting: none` | | `pointer-fine` | `pointer: fine` | | `pointer-coarse` | `pointer: coarse` | | `pointer-none` | `pointer: none` | | `any-pointer-fine` | `any-pointer: fine` | | `any-pointer-coarse` | `any-pointer: coarse` | Negate with `not-` prefix: `not-dark`, `not-print`, `not-forced-colors`, etc. ### Container Queries | Variant | Min-width | |---------|-----------| | `@3xs` | 16rem | | `@2xs` | 18rem | | `@xs` | 20rem | | `@sm` | 24rem | | `@md` | 28rem | | `@lg` | 32rem | | `@xl` | 36rem | | `@2xl` | 42rem | | `@3xl` | 48rem | | `@4xl` | 56rem | | `@5xl` | 64rem | | `@6xl` | 72rem | | `@7xl` | 80rem | | `@[{value}]` | `width >= {value}` | | `@max-[{value}]` | `width < {value}` | Container: `@container` class on parent, or `@container/{name}` for named containers. ### State Variants | Variant | Description | |---------|-------------| | `open` | `
` or `` is open, or `:popover-open` | | `inert` | Element has `inert` attribute | | `starting` | `@starting-style` for entry animations | ### Parent/Sibling State **Group** (style based on parent): ```html
...
``` ```css .group-hover\:text-blue-500 { &:is(:where(.group):hover *) { color: ... } } ``` - `group-hover`, `group-focus`, `group-active`, etc. - Named: `group/{name}` → `group-hover/{name}` - Arbitrary: `group-[.is-active]:block` **Peer** (style based on sibling): ```html ... ``` ```css .peer-invalid\:text-red-500 { &:is(:where(.peer):invalid ~ *) { color: ... } } ``` - `peer-hover`, `peer-focus`, `peer-invalid`, etc. - Named: `peer/{name}` → `peer-checked/{name}` - Note: peer must come BEFORE the styled element **In** (implicit group, no class needed on parent): - `in-hover`, `in-focus`, etc. Also: `group-has-*`, `peer-has-*` for styling based on descendants of group/peer. ### Child Selectors | Variant | Description | |---------|-------------| | `*` | Direct children (`& > *`) | | `**` | All descendants (`& *`) | ### ARIA States | Variant | Selector | |---------|----------| | `aria-busy` | `[aria-busy="true"]` | | `aria-checked` | `[aria-checked="true"]` | | `aria-disabled` | `[aria-disabled="true"]` | | `aria-expanded` | `[aria-expanded="true"]` | | `aria-hidden` | `[aria-hidden="true"]` | | `aria-pressed` | `[aria-pressed="true"]` | | `aria-readonly` | `[aria-readonly="true"]` | | `aria-required` | `[aria-required="true"]` | | `aria-selected` | `[aria-selected="true"]` | | `aria-[{attr}={value}]` | Arbitrary ARIA attribute | ### Data Attributes - `data-{name}` → `[data-{name}]` - `data-[{name}={value}]` → `[data-{name}="{value}"]` ### RTL/LTR | Variant | Description | |---------|-------------| | `rtl` | `[dir="rtl"]` | | `ltr` | `[dir="ltr"]` | ### Feature Queries - `supports-[{feature}]:{utility}` → `@supports ({feature})` - `supports-[display:grid]:grid` - `not-supports-[{feature}]:{utility}` ### Arbitrary Variants Custom selectors in brackets: - `[&.is-active]:bg-blue-500` - `[&_p]:mt-4` (underscore = space) - `[@media(min-width:900px)]:flex` --- ## Theme System ### @theme Directive ```css @import "tailwindcss"; @theme { --color-brand: #3b82f6; --font-display: "Inter", sans-serif; --spacing: 0.25rem; } ``` ### Theme Namespaces | Namespace | Generates | |-----------|-----------| | `--color-*` | Color utilities: `bg-*`, `text-*`, `border-*`, `fill-*`, `stroke-*`, etc. | | `--font-*` | `font-*` utilities | | `--text-*` | `text-*` font-size utilities | | `--font-weight-*` | `font-*` weight utilities | | `--tracking-*` | `tracking-*` letter-spacing | | `--leading-*` | `leading-*` line-height | | `--breakpoint-*` | `sm:`, `md:`, etc. variants | | `--container-*` | `@sm:`, `@md:`, etc. + `max-w-*`, `w-*` | | `--spacing` | Base spacing multiplier for `p-*`, `m-*`, `gap-*`, `w-*`, `h-*`, etc. | | `--radius-*` | `rounded-*` utilities | | `--shadow-*` | `shadow-*` utilities | | `--inset-shadow-*` | `inset-shadow-*` utilities | | `--drop-shadow-*` | `drop-shadow-*` utilities | | `--text-shadow-*` | `text-shadow-*` utilities | | `--blur-*` | `blur-*` utilities | | `--perspective-*` | `perspective-*` utilities | | `--aspect-*` | `aspect-*` utilities | | `--ease-*` | `ease-*` timing functions | | `--animate-*` | `animate-*` animations | ### Overriding Defaults ```css @theme { --color-*: initial; /* Clear all default colors */ --*: initial; /* Clear entire default theme */ /* Then define your own */ --color-primary: #3b82f6; } ``` ### Animation Keyframes ```css @theme { --animate-fade-in: fade-in 0.3s ease-out; @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } } ``` Defining keyframes inside `@theme` ensures they are only emitted if the animation is used. ### Theme Options **inline** — Inline values directly in utilities instead of using CSS variables: ```css @theme inline { --color-primary: #3b82f6; } /* bg-primary outputs: background-color: #3b82f6; */ /* instead of: background-color: var(--color-primary); */ ``` **static** — Always emit CSS variables, even if not used in any utility: ```css @theme static { --color-primary: #3b82f6; } /* Always emits: --color-primary: #3b82f6; in :root */ ``` --- ## Directives ### @import Import CSS files, including Tailwind itself: ```css @import "tailwindcss"; ``` ### @source Specify additional source files for class detection: ```css @source "../node_modules/@my-company/ui-lib"; ``` ### @utility Define custom utilities that work with variants: ```css @utility tab-4 { tab-size: 4; } ``` ### @variant Apply a Tailwind variant to styles in custom CSS: ```css .my-element { background: white; @variant dark { background: black; } } ``` ### @custom-variant Create a custom variant: ```css @custom-variant theme-midnight (&:where([data-theme="midnight"] *)); ``` Usage: `theme-midnight:bg-black` ### @apply Inline utility classes in custom CSS: ```css .select2-dropdown { @apply rounded-b-lg shadow-md; } ``` ### @reference Import stylesheet for reference without emitting CSS (for Vue/Svelte `