Reduced motion
How components follow the reduced motion preference, and how to force a subtree to play or stay still.
#Default behaviour
When the user enables reduced motion in their OS (prefers-reduced-motion: reduce), components adapt automatically:
- Entrance animations render their final state without moving or fading.
- WebGL backgrounds draw a single still frame and stop rendering.
- Looping CSS animations stop.
#usePrefersReducedMotion
Read the same preference in your own components to keep the whole site consistent. It also respects any surrounding ReducedMotionProvider.
HeroVideo.tsx
import { usePrefersReducedMotion } from '@elyri/motion';
export function HeroVideo() {
const reduced = usePrefersReducedMotion();
return reduced ? <img src="/hero.jpg" alt="" /> : <video src="/hero.mp4" autoPlay muted loop />;
}#ReducedMotionProvider
Force a subtree to stay still (reduced) or play (reduced={false}) regardless of the system setting. Useful for thumbnail grids or an in-app “disable animations” toggle.
Thumbnail.tsx
import { Aurora, ReducedMotionProvider } from '@elyri/motion';
export function Thumbnail({ playing }: { playing: boolean }) {
// Still until hovered, then play
return (
<ReducedMotionProvider reduced={!playing}>
<Aurora />
</ReducedMotionProvider>
);
}Forcing reduced={false} overrides the user’s system setting — only do it when the user explicitly opts in.
#Performance
- WebGL backgrounds pause offscreen and in background tabs, and resume when visible.
- Rendering is capped at 2× device pixel ratio by default to keep GPU cost in check on dense screens.
- During server rendering the preference is treated as “no reduction” and switches to the real value after hydration, avoiding mismatches.