Skip to content

Reduced motion

The Reduced motion component provides a toggle for enabling or disabling animations and transitions across your website. It respects the user’s system prefers-reduced-motion preference by default, persists user choices, and exposes a global JavaScript API for programmatic control. This is essential for users with vestibular disorders, motion sensitivity, or those who simply prefer a calmer browsing experience.

  • Accessibility settings panels
  • User preference controls
  • Sites with significant animations
  • WCAG compliance (Success Criterion 2.3.3)
  • Command palette / launcher integration
  • Supporting users with vestibular disorders

Click the toggle below to switch between normal and reduced motion mode:

Try using keyboard navigation (Tab + Enter/Space) to toggle!

Learn how to implement the ReducedMotion component in your project.

---
import { ReducedMotion } from 'accessible-astro-components'
---
<!-- Default - respects system preference -->
<ReducedMotion />
<!-- With custom icons -->
<ReducedMotion>
<Icon name="ion:play-outline" slot="off" />
<Icon name="ion:pause-outline" slot="on" />
</ReducedMotion>
<!-- Force reduced motion on by default -->
<ReducedMotion initialMode="on" />
<!-- Force animations on by default (ignores system preference) -->
<ReducedMotion initialMode="off" />

Configure the ReducedMotion component using these available props to customize its behavior and appearance.

PropTypeDefaultDescription
initialMode'on' | 'off' | 'auto''auto'Sets the initial mode. ‘auto’ respects system preference
labelstring'Toggle Reduced Motion'Accessible label for the toggle button
classstring''Additional CSS classes to apply

The ReducedMotion component supports named slots for customizing the icons displayed in normal and reduced motion modes.

SlotDescription
offIcon or content to display when animations are enabled
onIcon or content to display when reduced motion is active

The ReducedMotion component exposes a global window.reducedMotion API for programmatic control. This is useful for integrating with command palettes, launchers, or other UI elements.

// Toggle reduced motion mode
window.reducedMotion.toggle()
// Enable reduced motion (disable animations)
window.reducedMotion.enable()
// Disable reduced motion (enable animations)
window.reducedMotion.disable()
// Check if reduced motion is enabled
window.reducedMotion.isEnabled() // returns boolean

The component dispatches a reducemotion:change custom event when the mode changes:

document.addEventListener('reducemotion:change', (e) => {
console.log('Reduced motion enabled:', e.detail.enabled)
})

The component automatically listens for launcher:action events with action: 'toggle-reduced-motion', making it compatible with the Accessible Astro Launcher out of the box.

Accessibility isn’t an afterthought - it’s built into the core of this component. The ReducedMotion component is built with accessibility in mind:

  • Uses semantic button element
  • Proper ARIA attributes (aria-pressed, aria-label)
  • Maintains focus states
  • Persists across page loads using localStorage
  • Respects prefers-reduced-motion system preference by default
  • Disables all animations and transitions when active

Some users experience discomfort, dizziness, or nausea when viewing animations. This includes:

  • Users with vestibular disorders
  • Users with motion sensitivity
  • Users with certain cognitive disabilities
  • Users who simply prefer less motion

By providing this toggle, you give users control over their browsing experience.

Make the ReducedMotion component your own with custom styling while maintaining its accessibility features.

The component includes global styles that disable animations when reduced motion mode is active:

/* These styles are automatically applied */
.reduce-motion *,
.reduce-motion *::before,
.reduce-motion *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}

You can also check for reduced motion in your own animations:

.animated-element {
animation: slide-in 0.3s ease-out;
}
/* Disable animation when reduced motion is active */
.reduce-motion .animated-element {
animation: none;
}
/* Or use the media query for CSS-only solutions */
@media (prefers-reduced-motion: reduce) {
.animated-element {
animation: none;
}
}

See the ReducedMotion component in action with these practical examples.