Accessibility Features Built Into SVG Diagrams in Diagram-Design: WCAG 2.1 AA Compliance

The diagram-design repository enforces WCAG 2.1 AA accessibility standards through automated linting that requires every exported SVG to include semantic roles, descriptive text elements, and proper ARIA labeling.

The cathrynlavery/diagram-design repository generates diagrams with built-in accessibility features that ensure compliance with web standards. Every SVG produced by the export-diagram command undergoes validation by the lint_accessible_svgs function in scripts/lint-skin.py, which enforces a strict contract for assistive technology compatibility. These accessibility features are not optional add-ons but mandatory requirements built directly into the export pipeline.

Semantic Role Declaration

Every generated SVG must declare its semantic purpose using the role="img" attribute. This declaration signals to assistive technologies that the SVG represents meaningful content rather than decorative markup.

In scripts/lint-skin.py at lines 49-51, the validator explicitly checks that svg.attrs.get("role") != "img" triggers an error if the role is missing or incorrect. This enforcement ensures screen readers interpret the diagram as an image rather than generic XML content.

Accessible Name and Description Elements

The repository requires two specific child elements within every SVG to provide accessible text alternatives.

The Title Element

The <title> element must be the first child of the <svg> root and contain non-empty text. According to lines 96-104 in scripts/lint-skin.py, the linter verifies presence, DOM order, and content emptiness. This element serves as the accessible name for the diagram, typically mirroring the diagram's heading or purpose.

The Description Element

The <desc> element provides extended explanations for complex diagrams. Lines 108-112 enforce that this element exists and contains descriptive text, allowing screen reader users to understand visual relationships and data flows that sighted users perceive graphically.

Programmatic Association via ARIA

The linter enforces proper ARIA labeling through the aria-labelledby attribute. At lines 52-55 and 78-84 in scripts/lint-skin.py, the code validates that aria-labelledby references both the <title> and <desc> element IDs. This creates a programmatic link between the accessible name (title) and accessible description (desc) for screen reader announcements.

Strict ID Naming Conventions

To prevent ID collisions and ensure deterministic references, the repository implements a slug-based naming scheme.

Prefixed Identifiers

Lines 122-134 of the linter mandate that <title> and <desc> IDs must use the format <slug>-title and <slug>-desc, where <slug> represents the diagram's identifier. This prevents namespace collisions when multiple SVGs appear on the same page.

Duplicate Detection

The validator at lines 38-44 checks for duplicate IDs across the document, while lines 155-161 explicitly reject bare IDs like id="title" or id="desc" that lack the required slug prefix. These checks ensure that aria-labelledby references resolve to unique, predictable elements.

Decorative SVG Handling

For purely decorative graphics that should be ignored by assistive technologies, the repository supports aria-hidden="true". Lines 44-48 in scripts/lint-skin.py implement an early-exit check that suppresses all other accessibility validations when this attribute is present. This allows designers to include ornamental background patterns or spacer graphics without triggering lint errors.

Template Generation Support

When generating template SVGs during the design phase, scripts/lint-skin.py accepts placeholder IDs like [diagram-slug]-title through the allow_template_placeholders parameter (lines 66-70). This flexibility supports iterative development while maintaining the eventual accessibility contract for production exports.

Implementation Examples

Valid Accessible SVG

The following snippet satisfies all accessibility requirements for a diagram with the slug example-flowchart:

<svg role="img"
     aria-labelledby="example-flowchart-title example-flowchart-desc"
     width="800" height="600"
     xmlns="http://www.w3.org/2000/svg">
  <title id="example-flowchart-title">Flowchart of Process</title>
  <desc id="example-flowchart-desc">A step-by-step flowchart showing the stages of the process.</desc>
  <!-- diagram graphics go here -->
</svg>

Decorative SVG Exemption

For non-semantic decorative elements, use the exemption pattern:

<svg aria-hidden="true" width="800" height="600" xmlns="http://www.w3.org/2000/svg">
  <!-- purely decorative graphics -->
</svg>

Testing and Validation

The accessibility rules are exercised by scripts/test-lint-a11y.py, which confirms that the linter correctly accepts compliant SVGs while rejecting violations. When running the export-diagram command, any SVG failing these rules generates a lint error, preventing inaccessible diagrams from entering production workflows.

Summary

  • The lint_accessible_svgs function in scripts/lint-skin.py enforces mandatory accessibility for all exported SVGs
  • Every SVG must include role="img", a <title> element, a <desc> element, and aria-labelledby referencing both
  • IDs must follow the <slug>-title and <slug>-desc naming convention to prevent collisions
  • aria-hidden="true" exempts decorative SVGs from accessibility requirements
  • The test suite in scripts/test-lint-a11y.py validates compliance during the export process

Frequently Asked Questions

How does diagram-design validate SVG accessibility?

The repository uses the lint_accessible_svgs function located in scripts/lint-skin.py to programmatically inspect every exported SVG. This linter checks for required attributes, element ordering, and ID naming conventions, failing the build if any WCAG 2.1 AA requirements are missing.

What happens if an SVG fails the accessibility checks?

Any SVG that violates the accessibility contract triggers a lint error during the export-diagram command execution. The specific violation—such as missing title elements or incorrect ID formats—appears in the console output, preventing the inaccessible diagram from being committed or deployed.

Can I use diagram-design for decorative SVGs that don't need accessibility?

Yes. By adding aria-hidden="true" to the SVG root element, you signal that the graphic is purely decorative. When detected at lines 44-48 of scripts/lint-skin.py, this attribute suppresses all other accessibility checks, allowing the export to proceed without title or description elements.

How are ID collisions prevented in generated SVGs?

The linter enforces a slug-based prefix system at lines 122-134, requiring all accessible name IDs to use the format <diagram-slug>-title and <diagram-slug>-desc. Additionally, lines 38-44 check for duplicate IDs within the document, ensuring unique identification even when multiple diagrams appear on the same HTML page.

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 →