Motion

animation

Applying named CSS keyframes and animation tokens.

Overview

ClassDeclarations
animation:noneanimation: none;
animate-fadeanimation: var(--animate-fade);
animate-pinganimation: var(--animate-ping);
animate-flashanimation: var(--animate-flash);
animate-heartanimation: var(--animate-heart);
animate-jumpanimation: var(--animate-jump);
animate-pulseanimation: var(--animate-pulse);
animate-rotateanimation: var(--animate-rotate);
animate-shakeanimation: var(--animate-shake);
animate-zoomanimation: var(--animate-zoom);
animate-floatanimation: 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 indicator
animation: Ping indicator controls
Play opts into the actual CSS animation. Pause retains its time; Replay restarts even a finished one-shot. Readouts show native timeline time and progress, including delay and fill.
<!-- 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.

Rotate indicator
animation: Rotate indicator controls
Play opts into the actual CSS animation. Pause retains its time; Replay restarts even a finished one-shot. Readouts show native timeline time and progress, including delay and fill.
<!-- 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.

Loading spinner
animation: Loading spinner controls
Play opts into the actual CSS animation. Pause retains its time; Replay restarts even a finished one-shot. Readouts show native timeline time and progress, including delay and fill.
<!-- 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.

Apply conditionally
animation: Apply conditionally controls
Play opts into the actual CSS animation. Pause retains its time; Replay restarts even a finished one-shot. Readouts show native timeline time and progress, including delay and fill.
<!-- 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.

Add your animations
animation: Add your animations controls
Play opts into the actual CSS animation. Pause retains its time; Replay restarts even a finished one-shot. Readouts show native timeline time and progress, including delay and fill.
index.css
@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>


© 2026 Aoyue Design LLC.MIT License
Trademark Policy