Mermaid
A collection of Claude Skill to mirror https://mgifford.github.io/ACCESSIBILITY.md
npx -y skills add mgifford/accessibility-skills --skill mermaidAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Load this skill whenever the project uses Mermaid diagrams — flowcharts, sequence diagrams, class diagrams, Gantt charts, or any Mermaid-rendered visualization. Under no circumstances render a Mermaid diagram without an accessible title, description, and text-based alternative. Absolutely always add accTitle: and accDescr: (no %% prefix — that is the comment syntax and will be silently ignored) to every diagram.
SKILL.md
26.4 KB, as published. Nobody here has run it
Mermaid Diagrams Accessibility Skill
Canonical source:
examples/MERMAID_ACCESSIBILITY_BEST_PRACTICES.mdinmgifford/ACCESSIBILITY.mdThis skill is derived from that file. When in doubt, the example is authoritative.
Apply these rules when authoring, generating, or reviewing Mermaid diagrams. Only load this skill if the project uses Mermaid diagrams.
Core Mandate
Accessible Mermaid content depends on four layers: (1) the diagram source and its accessibility metadata, (2) the exact Mermaid renderer and configuration, (3) the generated SVG/raster output, and (4) how the publishing platform embeds and exposes that output. A generated Mermaid diagram is non-text content unless the rendered nodes/relationships are proven to have useful semantics — test the final published output, not just the source or an editor preview.
Before authoring, decide whether a diagram is even needed — a heading, short list, table, or few sentences may communicate the information more clearly. Mermaid is useful when relationships, sequence, branching, hierarchy, timing, or spatial grouping materially improve understanding.
Severity Scale (this skill)
| Level | Meaning |
|---|---|
| Critical | Diagram conveys essential information with no accessible title or alternative; metadata written with the wrong syntax so it's silently ignored |
| Serious | Title present but no description on a complex diagram; contrast fails |
| Moderate | No visible structured alternative for a complex diagram type; named edges lack context |
| Minor | Duplicate IDs; missing renderer-version verification |
Critical: Use the Correct accTitle/accDescr Syntax — No %% Prefix
%% is the Mermaid comment prefix. Lines written as %%accTitle … or
%%accDescr … are comments and are silently ignored — this produces no
accessibility metadata at all while looking like it works.
# WRONG — these are Mermaid comments and do nothing
%%accTitle This is ignored as a comment
%%accDescr This is also ignored as a comment
Correct syntax uses accTitle: and accDescr: directly, with no comment prefix:
flowchart TD
accTitle: Account recovery decision flow
A[Submit email address] --> B{Account found?}
B -->|Yes| C[Send recovery link]
B -->|No| D[Show recovery help]
Single-line description uses a colon:
flowchart LR
accTitle: Publishing workflow
accDescr: Content moves from drafting through accessibility review to publication.
A[Draft] --> B[Accessibility review] --> C[Publish]
For a multi-line description, omit the colon after accDescr and use braces:
flowchart TD
accTitle: Account recovery decision flow
accDescr {
A user submits an email address. If an account is found, the system sends
a recovery link and confirms that it was sent. If no account is found,
the system shows recovery help and offers a support contact.
}
A[Submit email address] --> B{Account found?}
B -->|Yes| C[Send recovery link]
B -->|No| D[Show recovery help]
Mermaid does not define a universal 100-character title limit or 500-
character description limit — write the shortest title that distinguishes
the diagram on the page, and keep the description concise enough to be
useful as an image description (move detailed steps into visible structured
HTML instead of stuffing them into accDescr).
Do not invent directives like %%a11y-node or %%a11y-edge — these are
not standard Mermaid syntax; they're comments unless a project-specific
preprocessor implements them, and should never be documented as Mermaid features.
Parse and render the source with the project's exact Mermaid version to
catch syntax-support and diagram-type differences — accTitle/accDescr
support varies by version and diagram type.
Writing Useful Titles and Descriptions
Title: identifies the subject, distinguishes it from others on the page, includes the diagram type only when it helps, avoids filenames/internal IDs/ generic labels ("Diagram"). Examples: "Account recovery decision flow", "Payment service request sequence", "Order states and permitted transitions".
Description: states the purpose, starting context, main elements/ participants, essential sequence/hierarchy/relationships, important decisions/exceptions/outcomes, and where a complete alternative is available. Do not merely list colors and shapes ("A blue rectangle points to a green diamond" describes appearance, not meaning) and do not flatten every node label into one long sentence — that's hard to navigate and loses structure.
Also provide a visible title/description — a page heading or figure caption helps everyone, not just AT users:
<figure aria-labelledby="recovery-flow-heading">
<h2 id="recovery-flow-heading">Account recovery flow</h2>
<pre class="mermaid">
flowchart TD
accTitle: Account recovery decision flow
accDescr: A recovery request either sends a link or offers additional help.
A[Submit email address] --> B{Account found?}
</pre>
<figcaption><a href="#recovery-flow-description">Read the account recovery steps</a>.</figcaption>
</figure>
(The > escaping is only needed when Mermaid source is embedded directly
in HTML — Markdown Mermaid fences don't need it.)
Serious: Provide a Visible Structured Alternative for Complex Diagrams
accDescr creates an SVG description, not a navigable document structure.
Complex diagrams need visible HTML with headings, lists, tables, and links.
| Mermaid diagram type | Useful structured alternative |
|---|---|
| Flowchart / decision tree | Ordered steps + nested lists or a decision table (conditions → outcomes) |
| Sequence diagram | Participant list + chronological message table |
| State diagram | State definitions + transition table (trigger, source, destination, outcome) |
| Class diagram | Class definitions, properties, methods, inheritance, relationship table |
| Entity relationship | Entity definitions, keys, attributes, cardinality, relationship table |
| Gantt / timeline | Task/event table with dates, duration, owner, status, dependencies |
| Pie/XY/quadrant/radar/Sankey | Summary of findings + underlying data table with units |
| Mind map / tree | Properly nested heading or list hierarchy |
| Architecture/C4/block | Component inventory, responsibilities, boundaries, relationship table |
| Git graph | Chronological branch/merge/release history |
| User journey | Ordered stages, goals, actions, emotions, barriers, opportunities |
<section id="recovery-flow-description" aria-labelledby="recovery-flow-description-heading">
<h3 id="recovery-flow-description-heading">Account recovery steps</h3>
<ol>
<li>The user submits an email address.</li>
<li>The system checks for an account:
<ul>
<li>If found, send a recovery link and confirm it was sent.</li>
<li>If not found, show recovery help and offer support.</li>
</ul>
</li>
</ol>
</section>
Keep alternatives synchronized — generate the diagram and its alternative from the same reviewed data model when possible; if maintained separately, require both in the same change, compare nodes/values/edges, and assign an owner for content review. Do not expose raw Mermaid source as the only alternative — it may help developers but is not an equivalent explanation for all users.
Serious: Understand Mermaid's Generated SVG (Do Not Hand-Author a Different Pattern)
Current Mermaid documentation states the renderer automatically adds
aria-roledescription based on diagram type, and when accTitle/accDescr
are provided, generates <title>/<desc> elements with aria-labelledby
referencing the title and aria-describedby referencing the description
— separately, not both combined into one aria-labelledby:
<svg aria-labelledby="generated-title-id"
aria-describedby="generated-description-id"
aria-roledescription="flowchart-v2"
id="generated-diagram-id">
<title id="generated-title-id">Account recovery decision flow</title>
<desc id="generated-description-id">A recovery request either sends a link or offers additional help.</desc>
</svg>
Do not rewrite both as one aria-labelledby value without a tested
reason — a label identifies the image; a description provides additional
information; they're distinct relationships. Exact IDs/classes/attributes
can change by Mermaid version — don't copy generated IDs into source or
depend on undocumented internal class names.
Node-by-node semantics are not automatic. accTitle/accDescr describe
the diagram as a whole — they do not make every node/edge/arrow a useful
accessible object. Do not automatically add role="list"/role="listitem"
to generated SVG groups — a visual layout is not necessarily a list, DOM
order may not match reading order, and list semantics can't express
branching, cardinality, or graph relationships. If users need to inspect
individual items, build and test a purpose-specific interactive component —
generated SVG internals are a fragile foundation for a complex widget.
IDs need to be unique in the final HTML document (not across unrelated
pages). Let Mermaid manage its generated IDs; check for duplicates when
several inline diagrams share a page; use deterministicIds config for
stable snapshot testing; preserve every referenced ID through sanitization/export.
Serious: Embedding and Export Modes Change the Rules
| Mode | Responsibility |
|---|---|
| Inline SVG generated in the page | Preserve generated title/description/ARIA references, language, styles, unique IDs |
External SVG via <img> | Give the HTML alt — do not assume the SVG's internal title/desc are exposed |
| Raster PNG/JPEG | HTML alt + long structured alternative in HTML |
<object>/iframe | Useful accessible name on the embedding element; test entry/exit; external HTML alternative |
| CSS background image | Decoration only, or provide the info in ordinary HTML |
| PDF/office-document export | Document tags, alt text, reading order — SVG metadata is not a substitute |
| Markdown platform renderer | Test the platform's exact Mermaid version, sanitizer, theme, and output |
<figure>
<img src="account-recovery-flow.svg"
alt="Account recovery either sends a reset link or provides additional support."
width="960" height="540">
<figcaption><a href="#recovery-flow-description">Read the complete account recovery steps</a>.</figcaption>
</figure>
Do not leave HTML alt empty just because the source SVG contains <title>/<desc>.
Choosing Clear Diagram Content
Nodes/participants: human-readable labels, not internal IDs; expand uncommon abbreviations; keep labels concise but meaningful; give visually similar nodes distinct textual labels; don't use shape alone to distinguish a decision/process/database/external system.
Edges/relationships: label branches when the outcome isn't otherwise clear — "Approved"/"Needs revision" over generic "Yes"/"No"; preserve direction and source→destination meaning in the alternative; explain unlabeled relationships depending on line style or position; don't use connector color alone to encode status or relationship type.
Reading order/layout: choose a direction matching content and document language; reduce line crossings; avoid layouts implying relationships through proximity alone. Visual placement is not a programmatic reading order — state the intended sequence/hierarchy in the description and structured alternative.
Moderate: Color and Contrast
Apply WCAG 2.2 ratios: normal text ≥4.5:1; large-scale text ≥3:1 (don't treat 18 CSS pixels alone as the large-text threshold — check WCAG's actual definition); visual information required to understand meaningful nodes/ boundaries/connectors/states ≥3:1 (WCAG 1.4.11). Not every decorative fill needs 3:1 against every neighboring fill when labels/outlines preserve the information. Use WCAG 2.x contrast for WCAG 2.2 conformance — APCA/WCAG 3 work is research to monitor, not a substitute test.
Combine color with: direct labels, line styles, patterns, icons with text alternatives, border treatments, or values in the structured alternative — for status, ownership, participant groups, critical paths, and selected states.
Test actual themes — centralize theme configuration rather than styling
individual elements by unstable internal selectors; test text/fills/borders/
connector lines/arrowheads/labels/focus/data marks in every supported light
and dark presentation and inside the actual background/container colors;
test forced-colors mode and keep the structured alternative usable when SVG
styling is lost. Do not assume selecting Mermaid's dark theme or adding a
prefers-color-scheme rule automatically produces accessible dark mode —
recheck themes after Mermaid updates.
Responsive Layout, Zoom, and Reflow
Include a useful viewBox in exported SVG; don't clip the diagram at 200%/
400% zoom; let users open a larger view or download an SVG when that helps;
keep the visible title/summary/alternative/controls reflowable; test long
labels and translations; never disable browser zoom. WCAG 1.4.10's
two-dimensional-layout exception can apply to a complex diagram itself, but
the surrounding title, description, controls, and structured alternative
still need to reflow.
Serious: Keyboard and Interactive Diagrams
Static diagrams do not need tabindex="0" — keyboard focus should move
to links/buttons/controls, not every decorative SVG group. If a diagram is
visually scrollable, ensure keyboard users can reach and scroll its
container without becoming trapped, and still provide a structured
alternative that doesn't depend on 2D scrolling.
Avoid putting the only path to essential links/actions inside a diagram — provide visible HTML links/controls nearby. If Mermaid links/click actions are enabled: each link is keyboard reachable; purpose is understandable from its accessible name; focus is visible and unobscured; pointer and keyboard actions produce the same result; the accessible name includes the visible label; target size and hover/focus content meet applicable criteria; every action has an equivalent HTML path. Do not simulate a button with a non-focusable generated SVG group.
For interactive exploration (select nodes, expand branches, filter, inspect details), build an accessible interaction model outside the generated static SVG, or use a tested component — Mermaid source plus ARIA attributes does not by itself define an accessible graph-navigation widget.
Motion and Animation
Avoid decorative animation. If animation/auto-updates/moving paths are added
by a host or plugin: provide pause/stop/hide controls where WCAG 2.2.2
applies; respect prefers-reduced-motion; avoid flashes exceeding WCAG
thresholds; don't use motion as the only change indicator; keep the final
state available in text. Don't make accessibility claims about Mermaid
animation without testing the exact version/integration.
Critical: Secure and Stable Rendering
Accessibility and security can fail together when untrusted diagram source
can inject markup. Keep Mermaid's securityLevel: 'strict' default unless a
reviewed use case requires another mode — do not lower security merely to
add essential links (put them in HTML instead). Treat user-supplied Mermaid
source as untrusted input; use supported sanitization and a restrictive CSP;
pin Mermaid/renderer dependencies via the project's lockfile when
self-managed; for platform-managed rendering, record the observed version,
date, discovery method, and tested capabilities. Do not load production
dependencies from an unpinned @latest URL. Limit source size/complexity to
prevent rendering failures; render errors as accessible text without
exposing sensitive details.
Controlled vs. platform-managed renderers:
| Model | Version evidence | Responsibility |
|---|---|---|
| Self-managed | Package manifest, lockfile, container digest | Pin, review updates, test output, keep a rollback path |
| Platform-managed (GitHub.com, Pages, Enterprise) | Version probe, dated observation | Record what was observed, test required capabilities, maintain an alternative, recheck after platform changes |
| Pre-rendered static export | Version recorded by the export job | Preserve export with source and alternative; test the final embedding context |
GitHub.com Markdown, GitHub Enterprise Server, GitHub Pages, local previews, and exported files are separate rendering surfaces — do not infer support on one surface from successful rendering on another. GitHub Pages does not automatically inherit GitHub.com's Mermaid renderer; the Jekyll theme/plugin/build pipeline determines whether and how Mermaid renders there.
Discover a hosted version with the info diagram:
info
This is a live diagnostic, not a pinned dependency — it may change
without a commit, and only reports the renderer on the surface where it's
displayed. Record it as a dated plain-text observation, not the only
accessible record: Last manually observed on GitHub.com: Mermaid x.y.z on YYYY-MM-DD.
Verify capabilities per surface, not just the version number: required
diagram types parse and render; accTitle/accDescr produce the expected
title/description/ARIA relationships; the host's sanitizer preserves
required semantics; light/dark/forced-colors remain understandable; multiple
diagrams per page don't produce conflicting IDs; the structured alternative
remains available if rendering fails.
Authoring and Review Workflow
Before authoring: decide whether a diagram materially improves understanding; identify purpose/audience/essential relationships/alternative format; confirm the target renderer supports the diagram type and accessibility syntax.
During authoring: add valid accTitle:/accDescr: lines (no %%
prefix); use clear labels; keep visual complexity proportionate; avoid
color-only/shape-only meaning; write the structured alternative alongside
the source; keep essential links/controls in HTML.
Before publication: render with the pinned production version (or record the platform-managed version and verify capabilities); inspect the generated SVG and final accessibility tree; validate the structured alternative against the diagram; test all supported themes/zoom/viewports/exports; test the actual host (not just an editor preview); record reviewer/version/date/limitations.
AI-generated diagrams: treat as a draft — verify every node/edge/value/ relationship against source material; rewrite generic accessibility descriptions; check the structured alternative matches the final diagram; reject invented Mermaid directives; don't infer accessibility/security/ conformance from successful visual rendering alone.
Linting and Automated Validation
Source checks: the exact source parses with the target renderer;
accTitle: is present and not commented out (i.e., not prefixed with %%);
accDescr: or accDescr { ... } is present and not commented out; values
are non-empty; prohibited custom directives aren't mistaken for real syntax;
a complex diagram references a visible structured alternative. Don't enforce
arbitrary universal character-count limits.
Rendered-output checks: generated <title>/<desc> exist; aria-labelledby
resolves to the title; aria-describedby resolves to the description; IDs
unique in the final page; sanitization/optimization didn't remove referenced
elements; no unintended focusable descendants; interactive elements have
names/roles/states/keyboard behavior/visible focus; render errors exposed as text.
Contrast checks need actual rendered pairs (text vs. effective background, boundaries, connector lines, focus states) in every supported theme — "monochrome" is not a reason to skip contrast testing.
Automation cannot determine whether the description is equivalent, reading order is meaningful, or the diagram is understandable — manual and user review required.
Testing
- Content/equivalent-purpose: state the question the diagram should answer; identify every essential relationship/branch/value; answer using the visual diagram, then using only the title/description/structured alternative; compare available information and conclusions; correct both representations together
- Keyboard: confirm static SVG isn't an unnecessary Tab stop; operate every diagram link/control/popup; verify visible focus and logical order; enter/leave scrollable diagrams without a trap; confirm every action has an equivalent HTML path
- Screen reader: confirm the computed accessible name/description; check whether the diagram is exposed as image/graphic/document by the final host; read the structured alternative by headings/lists/tables; confirm no duplicate/excessive announcements
- Visual/low-vision: normal and large text; 200%/400% zoom; narrow viewports/orientations; every light/dark presentation; forced-colors mode; confirm labels/nodes/lines/arrowheads/legends stay visible; long translations don't overlap
- Export/platform: test the original Markdown/source preview AND the production page after sanitization/optimization; record whether each tested renderer is pinned or platform-managed; test inline SVG, external SVG, and raster variants; test print/PDF; test with JavaScript unavailable or rendering failed; test several diagrams on one page for duplicate IDs; retest after Mermaid/plugin/theme/host updates
Common Failures
| Failure | Correction |
|---|---|
Writing %%accTitle or %%accDescr | Use accTitle: and accDescr: without the %% comment prefix |
| Requiring arbitrary 100-char/500-char limits | Write concise useful metadata; use visible structure for detail |
| Treating successful rendering as proof of accessibility | Inspect the final SVG, accessibility tree, host, and alternative |
Depending only on <desc> for a complex diagram | Provide visible headings, lists, tables, or prose |
| Exposing raw Mermaid source as the only alternative | Provide a plain-language, task-appropriate representation |
| Adding list semantics to every generated SVG group | Treat the diagram as a whole, or build a tested purpose-specific interface |
Replacing aria-describedby with aria-labelledby for the description | Preserve distinct label and description relationships |
| Generating title IDs from timestamps/random strings | Let Mermaid manage IDs; use deterministicIds where stability is required |
Treating xmlns as a general accessibility attribute | Required for serialized standalone SVG, not universal inline-SVG metadata |
Inventing %%a11y-node/%%a11y-edge syntax | Use supported Mermaid syntax or a documented real preprocessing extension |
| Using 18 CSS pixels as the large-text threshold | Apply WCAG's actual large-scale text definition |
| Assuming a dark Mermaid theme passes dark-mode requirements | Test actual colors in every supported presentation |
| Making static diagrams keyboard focusable | Keep static graphics out of the Tab order |
Loading Mermaid from an unpinned @latest dependency | Pin and review the production renderer version |
| Describing a platform-managed renderer as pinned | Record observed version, date, discovery method, tested capabilities |
| Assuming GitHub Pages uses GitHub.com's Mermaid version | Identify the renderer supplied by the Pages theme/plugin/build pipeline |
Using securityLevel: 'loose' without need | Keep strict security defaults; put essential interaction in HTML |
Definition of Done Checklist
-
accTitle:present using correct syntax (no%%prefix), concise and unique -
accDescr:oraccDescr { ... }present, explains purpose and key relationships - Mermaid version confirmed/recorded for the actual publishing surface(s)
- Generated SVG verified:
<title>,<desc>,aria-labelledby(title) andaria-describedby(description) kept as separate relationships - Complex diagram has a visible structured alternative matched to its diagram type
- Diagram and alternative are synchronized from the same data/change
- All IDs unique within the final page
- Decorative elements excluded from the accessibility tree; no fabricated
role="list"on generated groups - Named edges include contextual labels ("Yes, proceed to X" not "Yes")
- Contrast verified in light, dark, and forced-colors modes
- Static diagrams are not unnecessary Tab stops; essential links exist as real HTML links too
- Each publishing surface (GitHub.com, GitHub Pages, local preview, exports) tested separately
-
securityLevel: 'strict'retained unless a reviewed exception is documented - Tested with a screen reader
Key WCAG Criteria
- 1.1.1 Non-text Content (A) — Critical if no title/alternative
- 1.3.1 Info and Relationships (A)
- 1.4.1 Use of Color (A)
- 1.4.3 Contrast Minimum (AA)
- 1.4.10 Reflow (AA)
- 1.4.11 Non-text Contrast (AA)
- 2.1.1 Keyboard (A)
- 2.4.7 Focus Visible (AA)
- 4.1.2 Name, Role, Value (A)
- 4.1.3 Status Messages (AA)
References
- Full best practices guide
- Mermaid diagram types reference
- Mermaid transformation best practices
- Mermaid: Accessibility Options
- Mermaid: Security
- GitHub: Checking your version of Mermaid
- WAI-ARIA 1.2:
aria-roledescription
Standards horizon: These rules target WCAG 2.2 AA. Monitor: https://www.w3.org/TR/wcag-3.0/