# How `aria-labelledby` and `prefers-reduced-motion` Work in Diagram-Design

> Learn how diagram-design implements accessibility with aria-labelledby for screen readers and prefers-reduced-motion to serve static diagrams for users sensitive to animation.

- Repository: [Cathryn Lavery/diagram-design](https://github.com/cathrynlavery/diagram-design)
- Tags: deep-dive
- Published: 2026-08-18

---

**The diagram-design repository uses `aria-labelledby` to wire SVG diagrams to semantic `<title>` and `<desc>` elements for screen reader announcements, while employing `prefers-reduced-motion` CSS media queries and JavaScript detection to serve static frames to users with vestibular sensitivities.**

Diagram-design is an open-source SVG diagramming framework that embeds accessibility directly into its markup templates and validation pipelines. The repository enforces WCAG-compliant patterns through automated checks in `cathrynlavery/diagram-design`, ensuring that every diagram remains perceivable to assistive technology users and comfortable for those who require reduced motion. This article examines the specific implementations of `aria-labelledby` and `prefers-reduced-motion` based on the actual source code.

## Semantic SVG Accessibility with aria-labelledby

### Wiring Diagrams to Title and Description Elements

Every SVG diagram in the repository carries `role="img"` and references two descriptive elements via the `aria-labelledby` attribute. According to the validation logic in [`skills/diagram-design/scripts/self_check.py`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/scripts/self_check.py), the attribute must list the `<title>` element ID first, followed by the `<desc>` element ID. This ordering ensures screen readers announce a concise label before the longer explanation, providing hierarchical context for complex diagrams.

The validation script programmatically inspects each SVG to confirm that:
- **The first ID** in `aria-labelledby` points to a `<title>` element containing the diagram's name
- **The second ID** points to a `<desc>` element providing detailed description

### Automated Validation Pipeline

The repository's quality assurance relies on [`skills/diagram-design/scripts/self_check.py`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/scripts/self_check.py) to enforce semantic correctness. This script parses the `aria-labelledby` attribute value and verifies that the referenced elements exist and appear in the correct sequence, preventing accessibility regressions before diagrams reach production.

```html
<svg viewBox="0 0 1000 600"
     xmlns="http://www.w3.org/2000/svg"
     role="img"
     aria-labelledby="my-diagram-title my-diagram-desc">

  <title id="my-diagram-title">Order fulfillment process</title>
  <desc id="my-diagram-desc">
    Shows the flow from a customer order through support closure.
  </desc>

  <!-- diagram content … -->
</svg>

```

## Motion Sensitivity Support with prefers-reduced-motion

### CSS Media Query Fallbacks

For users with vestibular disorders or motion sensitivity, diagram-design implements a robust fallback strategy using the `prefers-reduced-motion` media query. As documented in [`skills/diagram-design/references/animation.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/references/animation.md), the CSS immediately displays the static final frame of any animation and suppresses playback controls when the user's system preferences indicate reduced motion.

The `@media (prefers-reduced-motion: reduce)` block targets the `data-motion-state="reduced"` attribute, ensuring that animated layers render at full opacity without transitions while hiding interactive controls that might trigger unwanted movement.

```css
@media (prefers-reduced-motion: reduce) {
  /* Show the final static frame and hide playback UI */
  .diagram[data-motion-state="reduced"] .playback-controls {
    display: none;
  }
  .diagram[data-motion-state="reduced"] .animated-layer {
    animation: none;
    opacity: 1; /* show the completed frame */
  }
}

```

### JavaScript Detection in template-motion.html

The motion-enabled template at [`skills/diagram-design/assets/template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/assets/template-motion.html) contains detection logic that runs before rendering. The script uses `window.matchMedia('(prefers-reduced-motion: reduce)')` to check system settings and applies `data-motion-state="reduced"` to the document root when necessary, immediately triggering the CSS fallbacks without requiring page reloads.

```javascript
const reduce = matchMedia('(prefers-reduced-motion: reduce)');
if (reduce.matches) {
  document.documentElement.dataset.motionState = 'reduced';
}

```

### Verification Scripts for Compliance

Two dedicated verification scripts ensure motion accessibility standards:
- **verify-motion.py**: Confirms that animated diagrams include the `prefers-reduced-motion` CSS fallback
- **verify-semantic-motion.py**: Validates that semantic motion alternatives exist for complex animations

These automated checks parse the diagram source files to ensure compliance before content reaches the main branch.

## Summary

- **Semantic SVG markup**: Every diagram uses `role="img"` and `aria-labelledby` to explicitly link to `<title>` and `<desc>` elements, ensuring screen readers announce diagram purpose and context in the correct order.
- **Automated accessibility validation**: The [`self_check.py`](https://github.com/cathrynlavery/diagram-design/blob/main/self_check.py) script enforces correct `aria-labelledby` ordering, while [`verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/verify-motion.py) and [`verify-semantic-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/verify-semantic-motion.py) ensure motion fallbacks exist and function correctly.
- **Reduced motion compliance**: CSS media queries detect `prefers-reduced-motion: reduce` to display static frames, supported by JavaScript detection in [`template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-motion.html) that sets `data-motion-state="reduced"` on the root element.
- **Template-driven implementation**: Base templates in [`assets/template.html`](https://github.com/cathrynlavery/diagram-design/blob/main/assets/template.html) and [`assets/template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/assets/template-motion.html) provide the foundational markup patterns that propagate accessibility features across all generated diagrams.

## Frequently Asked Questions

### How does diagram-design ensure screen readers announce diagram content correctly?

The repository enforces a strict markup pattern where every SVG carries `role="img"` and uses `aria-labelledby` to reference a `<title>` element (for the concise name) and a `<desc>` element (for the detailed description). The [`skills/diagram-design/scripts/self_check.py`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/scripts/self_check.py) validation script automatically checks that these IDs exist and appear in the correct order, preventing silent failures where screen readers might skip content or read descriptions out of context.

### What happens when a user enables prefers-reduced-motion in their browser?

When the system reports `prefers-reduced-motion: reduce`, the JavaScript in [`assets/template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/assets/template-motion.html) immediately sets `data-motion-state="reduced"` on the root HTML element. This triggers CSS rules that display the static final frame of any animation at full opacity while hiding playback controls via `display: none`, effectively eliminating vestibular triggers while preserving all semantic information.

### Which files contain the accessibility validation logic?

The primary validation occurs in [`skills/diagram-design/scripts/self_check.py`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/scripts/self_check.py) for semantic SVG markup, [`scripts/verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/verify-motion.py) for motion fallback detection, and [`scripts/verify-semantic-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/verify-semantic-motion.py) for semantic motion alternatives. These scripts parse the diagram source files to ensure compliance before content reaches production, catching missing `aria-labelledby` attributes or absent reduced-motion fallbacks during the CI pipeline.

### Can animated diagrams still convey information when motion is disabled?

Yes. The `prefers-reduced-motion` implementation in diagram-design always renders the **static final frame** of any animation sequence when motion is reduced. This guarantees that temporal information remains accessible as a complete visual state, ensuring no semantic content is lost for users who require reduced motion, while [`verify-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/verify-motion.py) confirms this fallback exists for every animated diagram.