Transitions and Animation
Purpose and Scope
Tailwind’s Transitions & Animation utilities let authors describe motion as composable class candidates instead of writing one-off CSS rules for each component. A class candidate is the token that appears in markup, such as duration-300, ease-out, transition-discrete, or animate-spin; the compiler turns recognized candidates into CSS only when they are needed. This page focuses on the reader-facing utility families for transition properties, durations, timing functions, delays, transition behavior, and animations, then maps those concepts to the repository entry points that compile and deliver the generated CSS.
Sources: packages/tailwindcss/src/index.ts, packages/tailwindcss/package.json
The official documentation groups these APIs under Transitions & Animation because they often work together. A hover interaction might combine transition-colors, duration-200, ease-out, and a state variant such as hover:bg-sky-600; a loading indicator might use animate-spin without any transition classes at all. The practical distinction is that transitions interpolate between two style states, while animations run a keyframed timeline. Tailwind treats both as utilities that can be combined with variants, arbitrary values, and theme variables, so teams can keep motion decisions consistent across markup.
Sources: packages/tailwindcss/src/index.ts
Core Utility Families
Use transition property utilities to decide which CSS properties should animate when a state changes. Common classes include transition, transition-all, transition-colors, transition-opacity, transition-shadow, transition-transform, and transition-none. These classes are usually paired with variants such as hover:, focus:, group-hover:, responsive breakpoints, or data and aria state variants. The important mental model is that the transition class does not cause a state change by itself; it tells the browser how to interpolate when another class or variant changes the final computed style.
Sources: packages/tailwindcss/src/index.ts
Duration and delay utilities control the timing envelope around that interpolation. duration-150, duration-300, and similar classes set the transition duration, while delay-75, delay-150, and arbitrary forms such as delay-[250ms] postpone the start. In Tailwind v4’s CSS-first model, theme variables are central to many utility families, and the official timing-function docs explicitly describe theme customization through --ease-* variables. Treat numeric duration and delay utilities as design-system tokens first, and use arbitrary values when a component genuinely needs a one-off timing value.
Sources: packages/tailwindcss/src/index.ts, packages/tailwindcss/package.json
Timing-function utilities control the easing curve used by transitions. The documented classes are ease-linear, ease-in, ease-out, ease-in-out, ease-initial, ease-(<custom-property>), and ease-[<value>]. The custom-property shorthand is useful when a motion system exposes named CSS variables, because it expands conceptually to a var(...)-based value without making markup noisy. When reviewing pull requests, prefer named theme variables or documented defaults for shared UI patterns, and reserve arbitrary cubic-bezier values for cases where design has specified a special curve.
Sources: packages/tailwindcss/src/index.ts
Transition behavior utilities cover a newer CSS capability: whether transitions can run for discrete property changes. The documented classes are transition-normal, which maps to normal transition behavior, and transition-discrete, which enables allow-discrete. This is especially relevant when an element changes between display states such as hidden and block while also fading or otherwise changing visual properties. In practice, pair transition-discrete with a property transition and state variants so the browser has both permission to transition a discrete change and an interpolable visual change to animate.
Sources: packages/tailwindcss/src/index.ts
Animation utilities set the CSS animation property directly. The official quick reference includes animate-spin, animate-ping, animate-pulse, animate-bounce, animate-none, animate-(<custom-property>), and animate-[<value>]. The predefined utilities use CSS variables and keyframes for common UI patterns: spinners, notification pings, skeleton loading pulses, and bouncing affordances. Because animations run independently from state changes, they should be used deliberately. Prefer transitions for simple interactive feedback, and use animation utilities for looping, timeline-based, or attention-directing motion.
Sources: packages/tailwindcss/src/index.ts, packages/tailwindcss/package.json
Relevant Source Files
packages/tailwindcss/src/index.ts— Core compiler entry point evidence. It imports candidate compilation, design-system construction, CSS parsing, theme handling, variant substitution, and compatibility hooks, which are the mechanisms that turn class candidates and CSS directives into output CSS.packages/tailwindcss/package.json— Public package metadata and export map fortailwindcss, including CSS entry files such asindex.css,theme.css,utilities.css, and package-level build/test scripts.package.json— Monorepo-level scripts for formatting, linting, building, testing, integration testing, UI testing, benchmarking, and playground commands that validate Tailwind behavior across packages.packages/@tailwindcss-browser/src/index.ts— Browser runtime evidence for Play CDN-style workflows. It creates a compiler, readsstyle[type="text/tailwindcss"]blocks, injects a default import when needed, and rebuilds CSS as page classes are discovered.packages/@tailwindcss-cli/src/index.ts— CLI entry point evidence. It parsestailwindcss,tailwindcss build, help, and canonicalization commands before dispatching to the build command.packages/@tailwindcss-node/src/index.ts— Node integration API evidence. It re-exports compile, instrumentation, optimization, source-map, path normalization, and environment helpers used by build-tool integrations.
System-to-Code Mapping
The tailwindcss package is the authoritative compiler package for these utilities. Its package metadata describes Tailwind as a utility-first CSS framework and exposes both JavaScript and CSS entry points. The CSS exports matter because projects commonly import tailwindcss, tailwindcss/theme, tailwindcss/preflight, or tailwindcss/utilities from CSS, while integrations use the JavaScript compiler entry points. This split lets the same transition and animation utility vocabulary work through Vite, PostCSS, the CLI, browser runtime, and Node-based tooling without every integration reimplementing the utility set.
Sources: packages/tailwindcss/package.json, packages/tailwindcss/src/index.ts
At the compiler level, packages/tailwindcss/src/index.ts is the place where CSS input, theme state, variants, compatibility hooks, and candidate compilation meet. The file imports compileCandidates, buildDesignSystem, the Theme class, CSS parser helpers, substituteAtImports, substituteFunctions, substituteAtApply, and variant substitution helpers. For this page’s utility families, that means classes such as easing, duration, transition behavior, and animation candidates participate in the same candidate compilation path as layout, color, and typography utilities, while variants determine where conditional selectors and media queries are applied.
Sources: packages/tailwindcss/src/index.ts
The package export map also explains why motion utilities are available through several installation paths. The root export provides the library entry point and style entry, while ./index.css, ./theme.css, ./preflight.css, and ./utilities.css expose CSS entry files directly. A user who writes @import "tailwindcss"; gets the standard CSS entry path, and a user who imports only tailwindcss/utilities is intentionally targeting generated utilities without the full layered entry file. These exports are part of the public contract that integrations and browser workflows rely on.
Sources: packages/tailwindcss/package.json
Execution Flow Across Runtimes
In a normal build-tool or CLI workflow, source files contain class candidates and CSS contains Tailwind imports or directives. The CLI entry point accepts root usage, a build subcommand, help flags, and a canonicalize command, then dispatches build work to the build command module. The important takeaway for transition and animation users is that the CLI is not a separate implementation of animate-spin or duration-300; it is a command-line route into the same Tailwind compilation model exposed by the core package.
Sources: packages/@tailwindcss-cli/src/index.ts, packages/tailwindcss/src/index.ts
The Node package provides the shared integration surface used by Node-based tools. Its entry point re-exports compile-related APIs, instrumentation, normalization, optimization, source-map helpers, and environment helpers. It also installs an ESM cache resolver hook when the runtime supports it, with specific handling for Bun and different Node hook APIs. For utility authors and application developers, this means the generated CSS for transition and animation classes can be produced inside richer toolchains while preserving dependency tracking, optimization, and source-map behavior around the core compiler.
Sources: packages/@tailwindcss-node/src/index.ts
The browser runtime demonstrates the Play CDN-style version of the same idea. It reads style tags whose type is text/tailwindcss, observes those sheets, injects @import "tailwindcss"; when the page has no explicit import, and creates a compiler with browser-specific stylesheet and module loaders. It keeps a set of classes already seen on the page so builds can pass only new candidates to the compiler. That design is important for animation demos and prototypes, where classes may appear dynamically as the DOM changes.
Sources: packages/@tailwindcss-browser/src/index.ts
Compact Utility Reference
| Family | Representative classes | CSS concern | Common pairing |
|---|---|---|---|
| Transition property | transition, transition-all, transition-colors, transition-opacity, transition-shadow, transition-transform, transition-none | Which properties interpolate | hover:, focus:, responsive variants |
| Duration | duration-75, duration-150, duration-300, duration-[250ms] | How long interpolation lasts | Property and easing utilities |
| Delay | delay-75, delay-150, delay-[250ms] | When interpolation starts | Staggered UI, menus, disclosure panels |
| Timing function | ease-linear, ease-in, ease-out, ease-in-out, ease-initial, ease-(--my-ease), ease-[cubic-bezier(...)] | Easing curve | Duration utilities and theme variables |
| Transition behavior | transition-normal, transition-discrete | Discrete transition behavior | Display or visibility state changes |
| Animation | animate-spin, animate-ping, animate-pulse, animate-bounce, animate-none, animate-(--my-animation), animate-[wiggle_1s_ease-in-out] | CSS animation timeline | Loading indicators, badges, skeleton states |
Examples and Usage Patterns
For a button hover interaction, start with a property utility and add timing controls: class="transition-colors duration-200 ease-out hover:bg-indigo-600". The transition utility identifies the property category, the duration sets the speed, the easing shapes the movement, and the hover variant supplies the state change. For a notification badge, use an animation utility on an absolutely positioned element, such as animate-ping, while the stable badge remains visible underneath. This separates decorative motion from the semantic element that communicates state.
Sources: packages/tailwindcss/src/index.ts
For components that change discrete display states, combine transition-discrete with a state-driven display change and an interpolable property such as opacity. The official docs demonstrate this idea with peer state variants and hidden or block display changes. The exact markup depends on your component architecture, but the principle is consistent: the browser needs a property to animate, a state change that alters styles, and allow-discrete behavior when a discrete property participates. Keep these classes close together in markup so future maintainers can understand the motion contract.
Sources: packages/tailwindcss/src/index.ts
For custom motion systems, prefer CSS variables and the parent theme layer over scattered arbitrary values. The animation and easing docs both include custom-property forms, which fit Tailwind v4’s CSS-first configuration model. A design system can define named animation or easing variables, then components use concise classes such as ease-(--ease-emphasized) or animate-(--animate-enter). Arbitrary values remain valuable for experiments and isolated effects, but variable-backed utilities are easier to audit, theme, and update across a large interface.
Sources: packages/tailwindcss/package.json, packages/tailwindcss/src/index.ts
Testing and Operational Signals
The root workspace scripts show how this behavior is expected to stay consistent across the monorepo. pnpm test runs Rust tests and Vitest, pnpm test:integrations runs the integration suite, and pnpm test:ui runs UI tests for the core package and browser package. Those commands matter for motion utilities because transition and animation classes are compiled through the same package surfaces as the rest of Tailwind. When changing compiler behavior, package exports, or runtime integration code, validate both the core compiler path and at least one delivery path.
Sources: package.json, packages/tailwindcss/package.json
As next steps, read the styling and variant pages before changing motion-heavy components, because most transition examples rely on conditional variants rather than standalone classes. Then read the package API, CLI, browser runtime, or Node API page that matches your installation path. If you are documenting or testing a new transition or animation behavior, capture both the visible class contract and the integration path that emits it, so users can trust the same class names in local builds, browser demos, and Node-powered tools.
Sources: packages/@tailwindcss-cli/src/index.ts, packages/@tailwindcss-browser/src/index.ts, packages/@tailwindcss-node/src/index.ts