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

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, 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 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.

<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, 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.

@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 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.

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 script enforces correct aria-labelledby ordering, while verify-motion.py and 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 that sets data-motion-state="reduced" on the root element.
  • Template-driven implementation: Base templates in assets/template.html and 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 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 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 for semantic SVG markup, scripts/verify-motion.py for motion fallback detection, and 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 confirms this fallback exists for every animated diagram.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →