Xzero UI
Pro library

Motion

Spring presets, easing and duration tokens, and reduced motion.

Principles

  • Motion explains cause and effect: what opened, what changed, and where it came from.
  • Animate transform and opacity. Nothing resizes in a single frame; widths and heights follow on a spring.
  • Actions repeated many times a minute, like keyboard navigation, do not animate.
  • Every animation keeps working when interrupted and has a reduced motion branch.

Springs

Springs live in components/xzero/lib/motion-tokens.ts and come with every Xzero install.

PresetValuesUse it for
spring.snappyvisualDuration: 0.26, bounce: 0Presses, toggles, thumbs, and small indicators.
spring.smoothvisualDuration: 0.4, bounce: 0Panels, height changes, and layout shifts. Never overshoots.
spring.morphvisualDuration: 0.42, bounce: 0Shared highlights, shape changes, and widths that follow content.
spring.responsivestiffness: 520, damping: 44Direct manipulation that must track the pointer closely.
spring.gentlestiffness: 340, damping: 34Larger layout changes that should feel calm.

Easing and duration

CSS transitions use the matching variables from the foundation.

TokenUse it for
--ease-standardDefault for UI transitions.
--ease-enterElements arriving on screen.
--ease-springA gentle settle, paired with --duration-spring.
--duration-fast160ms. Hover, color, and small state changes.
--duration-standard240ms. Panels and menus.
--duration-considered480ms. Rare, introductory reveals.

Using the tokens

toggle.tsx
import { motion, useReducedMotion } from "motion/react";import { motionTokens } from "@/lib/motion-tokens"; export function Thumb({ on }: { on: boolean }) {  const reduce = useReducedMotion();  return (    <motion.span      animate={{ x: on ? 20 : 0 }}      transition={reduce ? { duration: 0 } : motionTokens.spring.snappy}    />  );}
card.module.css
.card {  transition: background var(--duration-fast) var(--ease-standard);}

Reduced motion

When someone asks for reduced motion, keep the end state, focus, and feedback, and remove travel, looping, and parallax. A short opacity change is fine. In CSS:

panel.module.css
@media (prefers-reduced-motion: reduce) {  .panel {    transition: opacity var(--duration-fast) var(--ease-standard);  }}