Animation & Motion
Use animation intentionally — CSS transitions, keyframe animations, Framer Motion, gesture handling, page transitions, and reduced motion support.
Animation is where design engineers add unique value. A prototype has no motion curves, no hover states, no gesture feedback — but a shipped product needs all of them. Motion communicates hierarchy, confirms actions, and makes the interface feel physical rather than mechanical.
CSS Transitions vs Keyframes
The two CSS animation mechanisms serve different purposes and behave differently when interrupted:
| Mechanism | Interruptible? | Best for |
|---|---|---|
| CSS transitions | Yes — smoothly retarget to the latest state | Interactive elements: hover, open/close, toggle, focus |
| CSS keyframe animations | No — run on a fixed timeline once started | Decorative sequences: mount animations, loading indicators, attention-getters |
.element {
transition: transform 200ms ease, opacity 200ms ease;
}@keyframes fade-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
.element {
animation: fade-in 400ms ease-out;
}Users change their intent mid-interaction — menus open then close, dropdowns toggle then toggle back. Non-interruptible animations make the interface feel sluggish. Use transitions for anything the user interacts with.
Timing & Easing Tokens
Define motion durations and easing curves as design tokens:
@theme inline {
--duration-instant: 50ms;
--duration-fast: 100ms;
--duration-moderate: 200ms;
--duration-slow: 400ms;
--ease-out: cubic-bezier(0.0, 0.0, 0.2, 1);
--ease-in: cubic-bezier(0.4, 0.0, 1, 1);
--ease-inout: cubic-bezier(0.4, 0.0, 0.2, 1);
}| Duration | Typical use |
|---|---|
| 50ms | Feedback: hover states, focus rings |
| 100ms | Small element entrances |
| 200ms | Most UI transitions: modals, drawers, dropdowns |
| 400ms | Large-area transitions, page changes |
Framer Motion
When CSS transitions are not expressive enough — gesture-driven animations, shared layout animations, or orchestrated sequences — use Framer Motion.
Key Framer Motion patterns for design engineers:
| Pattern | API | When to use |
|---|---|---|
| Layout animation | motion.div layout | Items that reorder, appear, or disappear (lists, accordions, grids) |
| Presence animation | <AnimatePresence> | Elements that mount/unmount in UI (modals, toasts, notifications) |
| Drag gestures | drag, onDragEnd, dragConstraints | Swipeable cards, draggable lists, sortable grids |
| Scroll-driven | useScroll, useTransform, whileInView | Scroll reveals, parallax, progress indicators |
| Variants | variants={{ hidden: ..., visible: ... }} | Orchestrated child animations — stagger children with staggerChildren |
Gesture Handling
Touch and pointer gestures need libraries — do not hand-roll drag detection:
Use the drag prop from Framer Motion rather than raw pointer events. It handles velocity calculations, momentum, constraint boundaries, and accessibility fallbacks automatically. The same applies to use-gesture or @use-gesture/react for non-Framer projects.
Page Transitions
View Transitions API enables smooth page transitions without losing scroll position. Supported in Chromium and Safari.
For crossfade transitions, apply CSS:
::view-transition-old(root) {
animation: fade-out 200ms ease;
}
::view-transition-new(root) {
animation: fade-in 200ms ease;
}Reduced Motion
Always respect the user's motion preference. This is not optional:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}In Tailwind v4, use the motion-safe: and motion-reduce: variants:
<div
className="motion-safe:animate-fade-in motion-reduce:opacity-100"
>
{children}
</div>Do not disable all motion completely for users who prefer reduced motion. Replace animations with simpler alternatives — fade instead of slide, instant reveal instead of staggered entrance — rather than eliminating motion entirely. Some motion is functional (loading indicators, scroll position, state transitions) and removing it impairs usability.
Optical Alignment
Geometric centering is not always visually correct. Icons with pointed shapes (triangles, chevrons, arrows) often need a slight offset to look centred next to text or inside a button.
<button className="inline-flex items-center gap-2 px-4 py-2">
<PlayIcon className="size-4 mr-[1px]" aria-hidden="true" />
Play
</button>The same principle applies to button padding: the side with the icon needs slightly less padding than the text-only side because the icon's visual weight sits differently from text. When in doubt, adjust by 1-2px and check with your eyes rather than trusting the math.
Accessibility
Build interfaces that work for everyone. Accessibility is a technical requirement, not an afterthought. WCAG 2.2 AA is the professional baseline.
Deployment
Ship with confidence using automated CI/CD pipelines, environment-based configuration, preview deployments, rollback strategies, and production monitoring.