# How the Diagram-Design Animation System Handles Reduced-Motion Accessibility

> Learn how Diagram-Design's animation system respects reduced-motion accessibility by automatically disabling animations for users who prefer less motion, with manual control available.

- Repository: [Cathryn Lavery/diagram-design](https://github.com/cathrynlavery/diagram-design)
- Tags: accessibility
- Published: 2026-09-11

---

**The Diagram-Design library automatically detects the `prefers-reduced-motion` media query through a centralized `AnimationController` class that disables all transitions, keyframe animations, and physics simulations when users require minimal motion, while exposing a manual override API via `setMotionEnabled()`.**

The open-source **cathrynlavery/diagram-design** repository provides a data visualization framework with built-in accessibility considerations, documented comprehensively in [`docs/accessibility.md`](https://github.com/cathrynlavery/diagram-design/blob/main/docs/accessibility.md). Understanding how this **animation system handles reduced-motion accessibility** ensures your diagrams remain usable for people with vestibular disorders or other motion sensitivities. The implementation centralizes motion detection in a single controller that propagates state to all animated components.

## Core Detection in AnimationController

In [`src/animation/controller.ts`](https://github.com/cathrynlavery/diagram-design/blob/main/src/animation/controller.ts), the `AnimationController` class serves as the single source of truth for motion preferences. The constructor evaluates the browser's accessibility settings using the `prefers-reduced-motion` media query:

```typescript
export class AnimationController {
  readonly motionEnabled = !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  // ...
}

```

This boolean flag is exposed to the entire application, ensuring consistent behavior across all diagram types.

## Motion Disabling Strategies

When `motionEnabled` evaluates to `false`, the engine switches to a static rendering mode. The system alters behavior across four distinct domains:

- **Transitions**: CSS `transition` properties with easing functions are suppressed, applying final states instantly rather than interpolating over time.

- **Keyframe animations**: `@keyframes` sequences driven by `requestAnimationFrame` are skipped entirely, causing components to jump directly to their terminal frames.

- **Spring physics**: Libraries like `react-spring` or custom physics loops bypass interpolation calculations, snapping immediately to final target values.

- **Delay handling**: All timed delays between animation steps are suppressed, ensuring immediate layout completion.

## Component-Level Integration

Individual diagram components query the controller before initiating any motion. In [`src/components/BarChart.tsx`](https://github.com/cathrynlavery/diagram-design/blob/main/src/components/BarChart.tsx), the rendering logic checks the flag to determine whether to animate bar growth:

```typescript
import { useAnimationController } from 'diagram-design/animation';

export function CustomNode({ node }) {
  const { motionEnabled } = useAnimationController();

  // Apply a fade‑in only when motion is allowed
  const style = motionEnabled
    ? { animation: 'fadeIn 300ms ease-out' }
    : {};

  return <g style={style}>…</g>;
}

```

Similar patterns appear in `Sankey` and `ForceLayout` components, which all read the `motionEnabled` state before starting incremental layout updates.

## Developer Override API

Beyond automatic detection, the library exposes explicit control through [`src/api/motion.ts`](https://github.com/cathrynlavery/diagram-design/blob/main/src/api/motion.ts). The `setMotionEnabled()` function allows programmatic disabling of animations regardless of system preferences:

```typescript
import { setMotionEnabled } from 'diagram-design/animation';

setMotionEnabled(false); // forces static rendering

```

This function updates the internal controller’s flag and triggers a re-render without animations, guaranteeing compliance with accessibility requirements even when the media query is unavailable in older browsers.

## Integration Examples

### Automatic Reduced-Motion Handling

When rendering a standard bar chart, the library handles detection automatically:

```tsx
import { BarChart } from 'diagram-design';
import data from './sales.csv';

export default function SalesChart() {
  return <BarChart data={data} />;
  // Animations automatically disable if the user prefers reduced motion
}

```

### Forcing Static Rendering

For exported reports or print views, force reduced-motion mode explicitly:

```tsx
import { BarChart, setMotionEnabled } from 'diagram-design';

// Force static rendering for a printed report
setMotionEnabled(false);

export default function ReportChart() {
  return <BarChart data={reportData} />;
}

```

## Summary

- The **AnimationController** in [`src/animation/controller.ts`](https://github.com/cathrynlavery/diagram-design/blob/main/src/animation/controller.ts) centralizes reduced-motion detection using the `prefers-reduced-motion` media query.

- Components check the **`motionEnabled`** flag before executing CSS transitions, keyframe animations, or spring physics.

- When reduced motion is requested, animations execute as instant state changes rather than interpolated transitions.

- The **`setMotionEnabled()`** API in [`src/api/motion.ts`](https://github.com/cathrynlavery/diagram-design/blob/main/src/api/motion.ts) provides manual override capabilities for specific use cases like print rendering.

- All major diagram types including **BarChart**, **Sankey**, and **ForceLayout** respect these accessibility settings by default.

## Frequently Asked Questions

### How does Diagram-Design detect reduced-motion preferences?

The library queries the browser's `prefers-reduced-motion` media query during `AnimationController` initialization in [`src/animation/controller.ts`](https://github.com/cathrynlavery/diagram-design/blob/main/src/animation/controller.ts). The resulting boolean is stored in the readonly `motionEnabled` property that all components reference before starting animations.

### Can developers force reduced-motion mode for specific diagrams?

Yes. Import `setMotionEnabled` from `diagram-design/animation` and call it with `false` to override automatic detection. This updates the internal controller state and triggers an immediate re-render without motion, useful for generating static exports or print-specific layouts.

### What happens to physics-based animations when reduced-motion is enabled?

Spring physics and easing functions defined in [`src/animation/utils.ts`](https://github.com/cathrynlavery/diagram-design/blob/main/src/animation/utils.ts) bypass their interpolation loops when `motionEnabled` is `false`. Instead of calculating intermediate frames, these systems snap directly to final target values, eliminating vestibular triggers while preserving data visualization integrity.

### Which file contains the public API for motion control?

The primary developer interface resides in [`src/api/motion.ts`](https://github.com/cathrynlavery/diagram-design/blob/main/src/api/motion.ts), which exports both `setMotionEnabled()` for imperative control and `useAnimationController()` for React-style hook access. This file also re-exports utility types used by the animation system.