Reduced motion
What changes when someone asks for less motion, and how to respect it in your own code.
Reduced motion is the mode buttery switches to when a person asks their system for less motion, or an app sets it with ButteryProvider reducedMotion="always". Every preset and component follows it on its own; code that animates something itself reads the same setting.
What changes
- Springs become instant: things land in their new place on the next frame.
- Reveals and appearances become plain fades of 100ms at most.
- Loops stop, and confetti doesn't fire.
- Hover lifts and arrow nudges are skipped.
- Layout still updates: a panel that changes size still changes size, just without animating.
Setting it for an app
ButteryProvider's reducedMotion decides when motion is reduced for everything inside it.
| Value | What it does |
|---|---|
"user" | The default: follows the system |
"always" | Reduces motion for everyone |
"never" | Keeps full motion whatever the system says, such as from a setting of your app's own |
In your own code
Read the setting with a hook, or in CSS:
| Read it with | What it gives |
|---|---|
useMotionPreference() | "full" or "reduced" |
useButteryTransition(name) | The spring you name, or an instant one with reduced motion |
--bt-motion | In CSS, 1 with full motion and 0 with reduced, for durations worked out with calc() |
A progress bar that glides to its value on spring.smooth, and lands at once with reduced motion:
import type { ReactElement } from "react";
import { motion } from "motion/react";
import { useButteryTransition } from "@butteryui/core";
export function Progress({ done }: { readonly done: number }): ReactElement {
const transition = useButteryTransition("smooth");
return (
<motion.div
className="progress-bar"
animate={{ scaleX: done }}
transition={transition}
/>
);
}Related
- Principles
The ten rules every buttery animation follows, and the few things it never animates.
- Theming
Light and dark, compact density, and your own accent, grays and corners with createTheme.