Capítulo 25 de 29

Chapter 25: Transitions & Animation

Core Idea

transition-* utilities configure which properties animate on change and how (duration/delay/easing/discrete-value handling); animate-* utilities run a named, theme-defined @keyframes animation continuously — the two systems are independent (transitions react to a state change, animations loop or run on their own).

Reference Tables

transition-property: transition (a curated default list — color/background/border/outline/text-decoration-color/fill/stroke/gradient-stops/opacity/box-shadow/transform/translate/scale/rotate/filter/backdrop-filter/display/content-visibility/overlay/pointer-events — deliberately excludes width/height/margin etc. for performance), transition-all, transition-colors (narrower color-only subset), transition-opacity, transition-shadow, transition-transform, transition-none, transition-[<value>] (custom property list — must name individual transform sub-properties like scale/rotate/translate explicitly, not transform, if you want them to animate — see Upgrade Guide).

  • Default timing baked into every transition-* preset: cubic-bezier(0.4, 0, 0.2, 1) easing, 150ms duration (both overridable via duration-*/ease-*, or globally via the --default-transition-duration/--default-transition-timing-function theme variables).

transition-duration: duration-<number> (ms), duration-initial, duration-(<custom-property>), duration-[<value>].

transition-delay: delay-<number> (ms), delay-(<custom-property>), delay-[<value>].

transition-timing-function: ease-linear, ease-in, ease-out, ease-in-out (each theme-defined via --ease-*), ease-initial, ease-(<custom-property>), ease-[<value>].

transition-behavior: transition-normal, transition-discrete (allow-discrete — required to transition a property with a discrete value set, like animating display: noneblock via @starting-style, instead of it jumping instantly).

animation (--animate-* namespace, each paired with its own @keyframes): animate-spin (continuous rotation), animate-ping (scale+fade pulse, good for notification-dot attention effects), animate-pulse (opacity pulse, common loading-skeleton pattern), animate-bounce, animate-none. Custom animations are added the same way any theme token is — define --animate-<name> plus a matching @keyframes block inside @theme (see Theme chapter).

Code Examples


<button class="shadow transition-shadow duration-300 ease-out hover:shadow-lg">Hover me</button>


<div class="h-4 w-32 animate-pulse rounded bg-gray-200"></div>


<div class="hidden opacity-0 transition-discrete transition-all duration-300 open:block open:opacity-100 starting:open:opacity-0">
  ...
</div>
  • What it demonstrates: scoping a transition to just shadow for performance, the animate-pulse skeleton pattern, and transition-discrete + starting: combining to animate a display: none → block entrance with no JS.

Key Takeaways

  1. Prefer the narrower presets (transition-colors, transition-opacity, transition-shadow, transition-transform) over transition-all when only specific properties actually change — transition-all forces the browser to watch every animatable property.
  2. rotate/scale/translate are individual CSS properties in v4 — a custom transition-[...] list must name them individually (transition-[scale,opacity]), not rely on transform covering them (see Upgrade Guide).
  3. transition-discrete + @starting-style (starting: variant) is the modern no-JS way to animate an element appearing/disappearing via display, replacing old JS-timed "add the class after mount" tricks.
  4. animate-* runs independently of any state change — it's for continuous/looping effects (spinners, skeletons, pulses), not entrance/exit transitions.

Connects To

  • Transforms (next chapter): scale/rotate/translate utilities are what transition-transform/animate-spin typically animate.
  • Theme: --animate-* custom animations follow the same @theme + @keyframes pattern documented there.
  • Hover, Focus & Other States: starting: and other state variants are what typically trigger a transition.