# How Diagram-Design Ensures WCAG Accessibility Compliance: A Deep Dive into the SVG Accessibility Contract

> Learn how DiagramDesign ensures WCAG accessibility with its automated accessible SVG contract. Discover the details of SVG accessibility and compliance.

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

---

**Diagram-Design enforces WCAG accessibility through an automated "accessible SVG contract" that requires every diagram to include `role="img"` on the root `<svg>` element, validated by a dedicated linter and unit test suite.**

The `cathrynlavery/diagram-design` repository is an open-source diagramming tool that prioritizes inclusive design. Rather than relying on manual checks, the project embeds accessibility requirements directly into its CI pipeline. This article examines the technical implementation of WCAG compliance, from the linting rules in [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py) to the verification tests that prevent regressions.

## The Accessible SVG Contract: Core WCAG Requirement

The foundation of diagram-design's accessibility strategy is a **mandatory SVG contract** that addresses WCAG 2.1 Success Criterion 1.1.1 (Non-text Content). Every generated diagram must output an `<svg>` element with a valid ARIA role, enabling assistive technologies to recognize and announce the graphic correctly.

The contract specification lives in [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py), where the `lint_accessible_svgs` function validates each SVG node against this requirement. The implementation checks for the presence of `role="img"` and flags any violation as an **a11y** (accessibility) finding.

## Linter Enforcement in [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py)

The project's primary quality gate is [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py), a Python linter that runs automatically in CI. Within this file, line 340 contains the explicit accessibility check:

```python
add(svg.line, svg.offset, 'diagram <svg> must carry role="img"')

```

This line generates a categorized finding whenever an SVG lacks the required role attribute. The linter collects these under the **"a11y"** category, making violations immediately identifiable in build logs.

Running the linter with the `--all` flag executes the full validation suite:

```bash
python3 scripts/lint-skin.py --all

```

Any a11y finding causes the CI pipeline to fail, blocking merges of non-compliant diagrams.

### Linting Output Format

When the linter detects an accessibility violation, it produces output like:

```

a11y: diagram <svg> must carry role="img"

```

This format serves two purposes: it clearly identifies the issue category (a11y) and provides an actionable message for developers.

## Unit Test Verification

Automated testing prevents contract drift. The file [`scripts/test-lint-a11y.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/test-lint-a11y.py) contains unit tests that verify the linter correctly identifies valid and invalid SVGs.

The test suite constructs explicit test cases:

```python
VALID_SVG = '<svg xmlns="http://www.w3.org/2000/svg" role="img" …>'
INVALID_SVG = '<svg xmlns="http://www.w3.org/2000/svg" …>'

```

Tests assert that:
- The **invalid** SVG produces the finding `a11y: diagram <svg> must carry role="img"`
- The **valid** SVG produces no accessibility findings

This test coverage ensures the linter remains accurate as the codebase evolves.

## WCAG-Compliant SVG Examples

### Correct Implementation

```html
<svg xmlns="http://www.w3.org/2000/svg"
     role="img"
     aria-label="UML class diagram showing inheritance between User and Admin entities">
  <!-- diagram content -->
</svg>

```

This satisfies the accessible SVG contract by including `role="img"` and providing an `aria-label` for assistive technology announcement.

### Incorrect Implementation (Fails Linter)

```html
<svg xmlns="http://www.w3.org/2000/svg">
  <!-- diagram content -->
</svg>

```

Running [`lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/lint-skin.py) on this output produces:

```

a11y: diagram <svg> must carry role="img"

```

The CI pipeline would reject this diagram.

## Contributor Documentation and CI Integration

The project's [`README.md`](https://github.com/cathrynlavery/diagram-design/blob/main/README.md) includes a dedicated section, **"The accessible SVG contract (a11y)"**, that documents this requirement. Contributors are directed to run both the linter and unit tests before submitting changes:

```bash
python3 scripts/test-lint-a11y.py
python3 scripts/lint-skin.py --all --baseline

```

The [`.github/workflows/ci.yml`](https://github.com/cathrynlavery/diagram-design/blob/main/.github/workflows/ci.yml) configuration ensures these checks execute on every pull request, creating a **continuous validation pipeline** that guarantees WCAG compliance without manual oversight.

## Summary

- **Contract-based enforcement**: Every SVG must carry `role="img"` per the accessible SVG contract defined in [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py)
- **Automated linting**: The `lint_accessible_svgs` function generates a11y findings for violations, with line 340 containing the explicit error message
- **Test coverage**: [`scripts/test-lint-a11y.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/test-lint-a11y.py) validates linter behavior with explicit valid/invalid SVG test cases
- **CI integration**: GitHub Actions runs `lint-skin.py --all` to block non-compliant diagrams from merging
- **Contributor guidance**: README documentation ensures the accessibility requirement is discoverable and actionable

## Frequently Asked Questions

### What WCAG success criterion does the accessible SVG contract address?

The contract primarily addresses **WCAG 2.1 Success Criterion 1.1.1 (Non-text Content)**, which requires that all non-text content has a text alternative. By requiring `role="img"` on SVG elements, the contract enables assistive technologies to recognize diagrams as images and announce their `aria-label` or `aria-labelledby` attributes to users.

### Can the linter detect other accessibility issues beyond the role attribute?

The current implementation in [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py) focuses specifically on the `role="img"` requirement as the core contract. The test file [`scripts/test-lint-a11y.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/test-lint-a11y.py) suggests this is the primary automated check, though the README implies the contract may expand to cover color contrast and font requirements in future iterations.

### What happens if a contributor submits a diagram without `role="img"`?

The CI pipeline configured in [`.github/workflows/ci.yml`](https://github.com/cathrynlavery/diagram-design/blob/main/.github/workflows/ci.yml) runs `python3 scripts/lint-skin.py --all`. Any a11y finding, including the missing role violation, causes the check to fail and blocks the pull request from merging. Contributors must fix the issue and re-run local tests before resubmission.

### Is the accessible SVG contract customizable for different diagram types?

The contract applies universally to all SVG outputs from diagram-design. The `lint_accessible_svgs` function in [`scripts/lint-skin.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/lint-skin.py) inspects every `<svg>` node without exception, ensuring consistent accessibility across the entire diagram library regardless of diagram complexity or visual style.