How to Add Optional Accessible Motion to Diagrams in Diagram-Design
Diagram-Design supports optional accessible motion through a lightweight HTML contract that progressively enhances SVG-based diagrams with CSS animations and JavaScript controls while maintaining a fully static fallback for users who prefer reduced motion.
The Diagram-Design repository provides a declarative system for adding motion to diagrams without sacrificing accessibility standards. By implementing a specific data-attribute contract defined in skills/diagram-design/assets/template-motion.html, you can create animated visualizations that automatically degrade to accessible, static alternatives when users have motion sensitivities or disabled JavaScript.
Understanding the Motion Contract Architecture
The motion system centers on a single root controller coordinating multiple motion items. This architecture is enforced by continuous integration validators to ensure consistent accessibility across all diagrams.
The Root Controller (data-motion-root)
Every motion-enabled diagram requires exactly one container element marked with data-motion-root. As defined in the template source, this element accepts configuration attributes that determine animation behavior:
data-motion-mode: Set to"step"for step-through animations or"loop"for infinite cyclingdata-step-count: Integer defining total steps (maximum 12, strictly enforced by CI)data-frame="static": Indicates the initial static fallback state before JavaScript activation
The root element acts as the central controller that manages visibility states and synchronization across all child motion items.
Motion Items and Semantic Structure
Individual animation steps are marked with data-motion-item attributes and indexed using data-step="N" (1-based indexing). The contract enforces strict separation between semantic and decorative content:
Semantic items convey meaning and must include descriptive aria-label attributes. Decorative items—such as connector arrows or background fills—require data-motion-decorative combined with aria-hidden="true" and focusable="false" to ensure assistive technology ignores them.
The validator scripts/verify-semantic-motion.py specifically checks that non-decorative items carry meaningful labels and that decorative elements are properly hidden from the accessibility tree.
Playback Controls and Live Regions
User interface controls reside within a container marked data-motion-controls. Individual buttons use data-motion-action attributes accepting values including "play", "pause", "prev", "next", and "replay".
For screen reader users, a live region with role="status" and aria-live="polite" provides immediate spoken updates about the current step. This element uses data-motion-status and remains visually hidden while announcing changes to assistive technology.
Implementing the Motion Contract
To add optional accessible motion, import the motion template and implement the data-attribute contract within your SVG markup. The following example demonstrates a three-step process flow with decorative connectors and full accessibility support:
<link rel="stylesheet" href="assets/template-motion.html">
<main
data-motion-root
data-motion-mode="step"
data-step-count="3"
data-step-current="3"
data-frame="static"
data-static-frame="complete"
>
<h1>Sample Process Flow</h1>
<svg viewBox="0 0 600 200" role="img" aria-labelledby="sample-title sample-desc">
<title id="sample-title">Sample Process Flow</title>
<desc id="sample-desc">
A three-step process that shows request → validation → completion.
</desc>
<g data-motion-item data-step="1" aria-label="Step 1: Request received">
<rect x="20" y="50" width="150" height="80" fill="#f5f5f5" stroke="#2d3142"/>
<text x="95" y="100" text-anchor="middle" fill="#2d3142">Request</text>
</g>
<path
data-motion-item
data-motion-decorative
aria-hidden="true"
focusable="false"
d="M170 90 H380"
stroke="#4f5d75"
/>
<g data-motion-item data-step="2" aria-label="Step 2: Validation passed">
<rect x="380" y="50" width="150" height="80" fill="rgba(235,108,36,0.08)" stroke="#eb6c36"/>
<text x="455" y="100" text-anchor="middle" fill="#eb6c36">Validate</text>
</g>
<path
data-motion-item
data-motion-decorative
aria-hidden="true"
focusable="false"
d="M530 90 H590"
stroke="#4f5d75"
/>
<g data-motion-item data-step="3" aria-label="Step 3: Process complete">
<rect x="590" y="50" width="150" height="80" fill="#f5f5f5" stroke="#2d3142"/>
<text x="665" y="100" text-anchor="middle" fill="#2d3142">Done</text>
</g>
</svg>
<div data-motion-controls role="group" aria-label="Diagram playback controls">
<button type="button" data-motion-action="prev">Previous</button>
<button type="button" data-motion-action="play" aria-pressed="false">Play</button>
<button type="button" data-motion-action="pause" aria-pressed="true">Pause</button>
<button type="button" data-motion-action="next">Next</button>
<button type="button" data-motion-action="replay">Replay</button>
<span data-motion-status-visible aria-hidden="true">
Step <span data-motion-step-label>3</span> of 3
</span>
</div>
<p class="sr-only" data-motion-status role="status" aria-live="polite" aria-atomic="true">
Step 3 of 3 – Request received → Validation passed → Process complete.
</p>
</main>
The template-motion.html asset provides CSS animations and a @media (prefers-reduced-motion: reduce) media query that automatically disables animations, forces all items to full visibility, and hides playback controls when users prefer reduced motion.
Automated CI Validation
The repository enforces accessibility compliance through two Python validators that run in continuous integration:
scripts/verify-motion.py performs structural validation, ensuring:
- Exactly one
data-motion-rootexists per diagram - No more than 12 motion items are present
- The reduced-motion CSS media query is implemented
- A
<noscript>fallback element is provided for non-JavaScript environments
scripts/verify-semantic-motion.py checks accessibility semantics, verifying:
- Non-decorative items have meaningful
aria-labelattributes - Decorative items use
aria-hidden="true"andfocusable="false" - Status regions implement
role="status"andaria-live="polite"correctly
Both scripts prevent merging code that violates the motion contract, ensuring all diagrams remain accessible by default.
Summary
- Optional accessible motion relies on a declarative HTML contract using
data-motion-rootanddata-motion-itemattributes - The system supports step-through (
data-motion-mode="step") or loop modes with a maximum of 12 steps enforced byverify-motion.py - Decorative elements must use
data-motion-decorativewitharia-hidden="true"to remain invisible to assistive technology - Reduced-motion fallback activates automatically via CSS media queries in
template-motion.html, displaying a static version of the diagram - CI validation through
verify-motion.pyandverify-semantic-motion.pyguarantees compliance with WCAG guidelines
Frequently Asked Questions
How does the motion system handle users who prefer reduced motion?
The system uses a @media (prefers-reduced-motion: reduce) media query defined in template-motion.html that forces all data-motion-item elements to full visibility, disables CSS transitions and animations, and hides the data-motion-controls container. This happens automatically at the browser level without JavaScript detection, ensuring users with vestibular disorders receive a static, readable diagram immediately upon page load.
What is the maximum number of animation steps supported?
The contract enforces a maximum of 12 steps per diagram, as validated by scripts/verify-motion.py. This limit prevents cognitive overload and ensures step-through interfaces remain manageable. The validator checks the data-step-count attribute against the actual number of data-motion-item elements with unique data-step values. If your diagram requires more than 12 steps, refactor it into multiple linked diagrams or consolidate conceptual steps.
How do I mark decorative elements versus semantic content?
Semantic content—such as process steps or data points—requires a descriptive aria-label attribute on the data-motion-item element. Purely visual decorations like arrows or backgrounds must include data-motion-decorative, aria-hidden="true", and focusable="false" attributes. The verify-semantic-motion.py script validates this distinction, failing builds where decorative elements lack proper hiding attributes or where semantic items lack labels.
Is JavaScript required to view motion-enabled diagrams?
No. Optional accessible motion is implemented as progressive enhancement. When JavaScript is unavailable, the data-frame="static" attribute ensures the diagram renders in its complete state, and the required <noscript> element provides a text description of the full process. Motion controls and step-by-step animations only activate when JavaScript successfully loads, ensuring the core informational content remains accessible in all browsing contexts.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →