Every component ships in two flavors. Animated uses motion/react for spring physics. Static uses CSS transitions—no JS animation library required. Same props, same markup. Swap one for the other by changing the import path.
| Animated | Static | |
|---|---|---|
| Animation engine | Spring physics (motion/react) | CSS transitions |
| Bundle cost | ~30KB gzipped (motion lib) | ~0KB (CSS only) |
| Enter/exit | AnimatePresence, layout morphs | @keyframes via tw-animate-css |
| Gestures | whileHover, whileTap, drag | :hover, :active pseudo-classes |
| Reduced motion | Auto-respects system + MotionProvider | prefers-reduced-motion query |
If you're already using motion/react for page transitions or hero animations, go Animated. The library is already in your bundle—adding animated components costs almost nothing extra.
If you're building an admin panel, internal tool, or anything where bundle size matters more than bounce, pick Static. You save ~30KB and the components still feel responsive—they just won't have spring physics.
You can mix both. Use animated for the things users interact with most (modals, popovers, navigation), static for data tables and forms nobody lingers on.
Pulls in motion/react if you don't have it. Respects prefers-reduced-motion automatically.
There's a toggle in the sidebar. Switch it to see the install command, code examples, and dependency list for whichever variant you want. No need to mentally translate—docs update to match your choice.
Animated components accept a disableAnimation prop. Useful when you want the animated variant globally but need to turn it off in specific places:
<Button disableAnimation>
Skip the spring, keep the API
</Button>Or wrap your app in MotionProvider with reducedMotion="always" to disable everything at once.
The API is identical. Migration is three lines:
@/components/ui/button → @/components/ui/static/button (or reverse)motion/react from package.json if this is the last animated component