Cambio
Cambio is a simple shared animation component for React.
Cambio simplifies shared animations in React by removing the complexity that many developers face when setting up these interactions. By eliminating boilerplate code, it streamlines both implementation and maintenance workflows.
Built on Base UI's accessible primitives and Motion's powerful animation library, Cambio ensures your animations are both performant and inclusive by default.
For the source code, check out the GitHub.
Installation
pnpm add cambio
Setup
Cambio leverages Base UI's Dialog component to render popups outside of the main DOM hierarchy. To make portalled components always appear on top of the entire page, add the following style to your application layout root.
// layout.tsx
<body>
<div className="root">
{children}
</div>
</body>
// styles.css
.root {
isolation: isolate;
}
For more information, see the Base UI Documentation.
Usage
It can be used anywhere in your application as follows.
"use client";
import { Cambio } from "cambio";
export default function MyModal() {
return (
<Cambio.Root>
<Cambio.Trigger>{/* Your Trigger Content */}</Cambio.Trigger>
<Cambio.Portal>
<Cambio.Backdrop />
<Cambio.Popup>
<Cambio.Title />
<Cambio.Description />
<Cambio.Close />
{/* Your Additional Content */}
</Cambio.Popup>
</Cambio.Portal>
</Cambio.Root>
);
}
For complete code examples, refer to the examples directory.
Motion
Cambio leverages the power of Motion to provide a seamless animation experience. All components are built on Motion primitives, giving you fine-grained control over animations without the complexity.
You can easily customize transitions by passing a transition
prop to any component:
<Cambio.Popup transition={{ type: "spring", bounce: 0.2, duration: 0.4 }} />
This eliminates the need to wrap components in <motion.div />
elements while maintaining full Motion capabilities.
Presets
Cambio includes four built-in motion presets, each optimized for different interaction patterns. You can configure the motion preset globally at the root level.
snappy
- 240ms ease-out animations for quick, responsive interactions
smooth
- 300ms ease-in-out animations for balanced, general-purpose motion
bouncy
- Spring animations with organic movement for playful interfaces
reduced
- 10ms linear animations for accessibility compliance
<Cambio.Root motion="snappy" />
Variants
Configure different motion presets for different components when you need granular control over the animation experience. This is useful when you want each component to have its own distinct motion characteristics:
<Cambio.Root
motion={{
trigger: "snappy",
popup: "bouncy",
backdrop: "smooth",
}}
>
<Cambio.Trigger>{/* Uses snappy motion */}</Cambio.Trigger>
<Cambio.Portal>
<Cambio.Backdrop />
{/* Uses smooth motion */}
<Cambio.Popup>{/* Uses bouncy motion */}</Cambio.Popup>
</Cambio.Portal>
</Cambio.Root>
Overrides
Override motion for individual components. Component-level motion takes the highest priority, followed by motion variants, then global motion settings:
<Cambio.Root motion="smooth">
<Cambio.Trigger motion="snappy">{/* Overrides to snappy */}</Cambio.Trigger>
<Cambio.Portal>
<Cambio.Backdrop motion="reduced" />
{/* Overrides to reduced */}
<Cambio.Popup motion="bouncy">{/* Overrides to bouncy */}</Cambio.Popup>
</Cambio.Portal>
</Cambio.Root>
Snappy
Fast ease-out animations (240ms) for quick, responsive interactions. Ideal for buttons, toggles, and frequent actions where immediacy is key.
<Cambio.Root motion="snappy" />
Smooth
Balanced ease-in-out animations (300ms) for general-purpose motion. The default preset that works well for most modal and popup interactions.
<Cambio.Root motion="smooth" />
Bouncy
Spring animations with playful overshoot for engaging, organic movement. Perfect for delightful interactions and creative interfaces.
<Cambio.Root motion="bouncy" />
Dismissability
Cambio supports dismissible popups, allowing users to easily close the popup by dragging. You can configure this behavior at the root level.
<Cambio.Root dismissible />
Advanced Configuration
Customize dismissal sensitivity:
<Cambio.Root dismissible={{ threshold: 120, velocity: 600 }}>
<Cambio.Popup />
</Cambio.Root>
Accessibility
Cambio respects user accessibility preferences, specifically the prefers-reduced-motion
media query. By default, Cambio automatically detects and respects this system preference to provide a more accessible experience for users who prefer reduced motion.
<Cambio.Root reduceMotion={true} />
Why Cambio?
Cambio offers a unique combination of simplicity, accessibility, and powerful animation capabilities that sets it apart from other libraries.
Other libraries cater mainly towards image/video zooming. Cambio is not limited to do this. It's powered by Motion and Base UI which provides a more comprehensive solution for building shared animations in React applications.
This means you can create expanded states, draggable elements, and interactions that feel natural, all while maintaining accessibility for every user.
What you can create with it, is limited only by your imagination.
Support
For any issues or feature requests, please open an issue on GitHub.
You can also reach out to me on Twitter.