animation
Applying named CSS keyframes and animation tokens.
Overview
| Class | Declarations |
|---|---|
animation:none | animation: none;
|
animate-fade | animation: var(--animate-fade);
|
animate-ping | animation: var(--animate-ping);
|
animate-flash | animation: var(--animate-flash);
|
animate-heart | animation: var(--animate-heart);
|
animate-jump | animation: var(--animate-jump);
|
animate-pulse | animation: var(--animate-pulse);
|
animate-rotate | animation: var(--animate-rotate);
|
animate-shake | animation: var(--animate-shake);
|
animate-zoom | animation: var(--animate-zoom);
|
animate-float | animation: var(--animate-float);
|
animate-<name> | animation: <name>;
|
animation:<name>|<duration>|<…> | animation: <name> <duration> <…>;
|
Use animate-* for a complete animation token, or animation:* to supply native shorthand parts. Previews start paused; Play and Replay explicitly opt into motion. Portable snippets pause decorative animation for reduced motion and remove it in print.
Basic usage
Ping indicator
Use the ping token for a repeating ring. Keep the status in visible text so the message remains clear when the decoration is paused.
<!-- Ping ring · stable status text --><div class="flex items-center gap-md p-sm"> <svg aria-hidden="true" width="40" height="40" viewBox="0 0 40 40" class="text-blue fill-current"> <circle id="target" cx="20" cy="20" r="8" class="animate-ping transform-origin:center animation:none@print animation-play-state:paused@reduce-motion" /> <circle cx="20" cy="20" r="5" /> </svg> <span class="font-sm">Open for orders</span></div>Generated CSS
@layer theme { :root, :host { --animate-ping: ping 1s infinite }}@layer utilities { .animate-ping { animation: var(--animate-ping) }}@keyframes ping { 75% { transform: scale(2); opacity: 0 } to { transform: scale(2); opacity: 0 }}The preset grows the ring to twice its size and fades it out. The inner dot and status text remain still; the SVG has room for the full ring.
Rotate indicator
Use animate-rotate for a steady full turn, and animation-direction:reverse to turn counterclockwise.
<!-- Restoring data --><div class="flex items-center gap-md p-sm"> <svg id="target" aria-hidden="true" width="48" height="48" viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="2" class="text-blue animate-rotate animation-direction:reverse animation:none@print animation-play-state:paused@reduce-motion"> <circle cx="24" cy="24" r="17" opacity=".25" /> <path d="M24 8v16h12 M19 13l5-5 5 5" /> </svg> <span class="font-sm">Restoring data</span></div>The label remains stationary. In the preset, normal rotation goes clockwise; reversing the timeline also reverses its easing.
Advanced usage
Loading spinner
Offset eight SVG strokes through the preset one-second fade cycle. Negative delays place them at different points from the first frame.
<!-- Eight segments · one-second cycle --><div class="flex items-center gap-md p-sm"> <svg aria-hidden="true" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" class="text-blue"> <path id="target" d="M7.75 7.75l-2.15-2.15" class="animate-fade animation-delay:-.875s animation:none@print animation-play-state:paused@reduce-motion" /> <path d="M12 6V3" class="animate-fade animation-delay:-.75s animation:none@print animation-play-state:paused@reduce-motion" /> <path d="M16.25 7.75l2.15-2.15" class="animate-fade animation-delay:-.625s animation:none@print animation-play-state:paused@reduce-motion" /> <path d="M18 12h3" class="animate-fade animation-delay:-.5s animation:none@print animation-play-state:paused@reduce-motion" /> <path d="M16.25 16.25l2.15 2.15" class="animate-fade animation-delay:-.375s animation:none@print animation-play-state:paused@reduce-motion" /> <path d="M12 18v3" class="animate-fade animation-delay:-.25s animation:none@print animation-play-state:paused@reduce-motion" /> <path d="M7.75 16.25l-2.15 2.15" class="animate-fade animation-delay:-.125s animation:none@print animation-play-state:paused@reduce-motion" /> <path d="M6 12H3" class="animate-fade animation-delay:0ms animation:none@print animation-play-state:paused@reduce-motion" /> </svg> <span class="font-sm">Loading resources</span></div>Each stroke fades from transparent to opaque. A 125ms offset separates adjacent segments, while the visible loading label stays readable with reduced motion or in print.
Apply conditionally
Keep the indicator static below sm, then enable animate-rotate at that breakpoint. Resize the real viewport before pressing Play.
<!-- Syncing resources --><div class="flex items-center gap-md p-sm"> <svg id="target" aria-hidden="true" width="48" height="48" viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="2" class="text-blue animation:none animation-iteration-count:infinite animation-timing-function:linear animation:none@print animation-play-state:paused@reduce-motion animate-rotate@screen@sm"> <circle cx="24" cy="24" r="17" opacity=".25" /> <path d="M24 8v16h12 M19 13l5-5 5 5" /> </svg> <span class="font-sm">Syncing resources</span></div>The native media query selects the animation. Print removes it; reduced motion pauses decoration until an explicit preview action.
Customization
Add your animations
Define named keyframes inside @theme, then reference that name with the native animation:* shorthand.
@theme { @keyframes slide-in-up { from { transform: translateY(100%); } to { transform: translateY(0); } }}Apply the custom animation using animation syntax:
<div class="animation:slide-in-up|var(--duration-slower)"></div>