PlantUML SVG accessibility: screen readers, WCAG, contrast
PlantUML’s default SVG is hostile to visually impaired users — no alt text, screen readers can’t read it, contrast fails color-blind users. Compliance scenarios (government, education, finance) require WCAG 2.1 AA. This is how to make PlantUML diagrams accessible.
Why SVG accessibility matters
Three user groups:
- Visually impaired — use screen readers (NVDA / JAWS / VoiceOver)
- Motor impaired — use keyboard or switch devices
- Color blind — need color + shape/text dual encoding
PlantUML’s default SVG — no <title> <desc> role attributes on any element; screen readers hit “Image, no description” and skip.
WCAG 2.1 AA three hard metrics
| Criterion | Requirement | PlantUML default |
|---|---|---|
| 1.1.1 Non-text content | Image must have alt or longdesc | ✗ no alt |
| 1.4.3 Contrast | Text vs background contrast ≥ 4.5:1 | ✓ default black on white usually passes |
| 2.4.7 Focus visible | Keyboard focus visible | ✗ no tabindex |
| 4.1.2 Name, role, value | Controls have accessible name | ✗ no aria-label |
Fix 1: title and desc directives
PlantUML 1.2020+ supports inline <title> and <desc>:
1 | @startuml login_flow |
title produces SVG with <title> element — screen reader announces “User Login Flow” as the diagram title.
But PlantUML’s title only emits <title>, not <desc> — for detailed description use post-processing.
Fix 2: caption directive (1.2023+)
1 | @startuml |
caption produces SVG with <desc> element — screen reader narrates the full description.
Fix 3: post-process to inject full a11y attributes
For a11y PlantUML doesn’t support natively, post-process with Python/Node:
1 | # make_accessible.py |
1 | python make_accessible.py architecture.svg "User Authentication Architecture" "Diagram showing user login flow with JWT token generation" |
The SVG now has:
<svg role="img" aria-label="..." aria-describedby="...">- embedded
<title><desc> - every node
<g tabindex="0" role="button" aria-label="...">
Screen reader can now narrate every node’s description, keyboard Tab key focuses each node.
Fix 4: contrast optimization
1 | @startuml |
WCAG AA requires:
- Text vs background contrast ≥ 4.5:1
- Large text (≥18pt or bold 14pt) contrast ≥ 3:1
PlantUML default colors — black text on white #000000 vs #FFFFFF = 21:1 (perfect). But light gray on dark gray fails.
WCAG AAA strict requires contrast ≥ 7:1 — text must be pure or near-black.
Fix 5: color blind adaptation
8% of men / 0.5% of women are color blind — red-green is the most common. PlantUML’s default theme distinguishes by red/green:
1 | skinparam sequence { |
Red-green color blind can’t see this — need shape + text + color triple encoding:
1 | skinparam Participant { |
Step numbers ①②③④ — color-blind users see order clearly too.
Fix 6: keyboard navigation post-process
1 | // keyboard-nav.js |
Tab focuses node → orange outline appears → Enter triggers click — fully keyboard-reachable.
Verification tools
WAVE (Web Accessibility Evaluation Tool)
Browser extension: https://wave.webaim.org/extension/
Open the page with the SVG → WAVE reports SVG a11y issues:
- Missing alt text
- Empty link
- Missing form label
axe DevTools
DevTools extension: run axe → list all a11y violations.
Lighthouse
Chrome DevTools → Lighthouse → Accessibility score. Target 100/100.
Manual testing
- macOS VoiceOver:
Cmd+F5to enable → Tab through → should hear each SVG node’s description - Windows NVDA: free screen reader → browse the page
- Keyboard only: unplug the mouse → Tab should focus every node
Field example: compliance-ready diagram
Government / medical / education / finance sites require WCAG 2.1 AA. PlantUML diagrams must:
1 | @startuml |
Supporting:
- SVG post-process adds
role="img"aria-label - Nodes get
tabindexaria-label - Page has a text version of “diagram description” paragraph (
<details><summary>Text Description</summary>...</details>) - Skip-navigation link lets users skip SVG
Key a11y HTML patterns
1 | <figure role="figure" aria-labelledby="diagram-title" aria-describedby="diagram-desc"> |
<img alt=""> — empty alt tells screen reader to skip the image itself; figcaption provides the description.
Field foot-guns
- PlantUML
titledoesn’t render longdesc — only emits<title>, detailed description needscaptionor post-process-injected<desc>. <svg role="img">must pair with alt — WAVE flags “SVG missing alternative content”; addaria-labelto<svg>itself.- Focus outline overridden by CSS — many themes set
*:focus { outline: none }, keyboard users see no focus. Never blanketoutline: none; only set on specific elements like buttons. - Color blind mode (Windows High Contrast) — SVG colors get force-replaced by OS, may become unreadable. Don’t rely on color alone.
- Print styles — colored SVG prints black-and-white, color-blind friendly but loses color info. Use
prefers-color-schememedia query to differentiate:1
2
3
4@media print {
svg .status-ok { fill: #000 ; }
svg .status-down { fill: #888 ; }
}
Decision tree
1 | Need a11y? |
Minimum a11y fix: add role="img" aria-label="..." to <svg>, post-process inject <title> <desc> — screen reader can read the diagram — 30 lines of Python fixes 80% of a11y issues.
- Title: PlantUML SVG accessibility: screen readers, WCAG, contrast
- Author: puml.online
- Created at : 2026-07-30 17:20:00
- Updated at : 2026-08-14 21:34:29
- Link: https://puml.online/blog/plantuml-svg-accessibility-en/
- License: This work is licensed under CC BY-NC-SA 4.0.