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.
Canonical source: examples/MERMAID_ACCESSIBILITY_BEST_PRACTICES.md in mgifford/ACCESSIBILITY.md
This 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
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 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
<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
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: or accDescr { ... } present, explains purpose and key relationships
Mermaid version confirmed/recorded for the actual publishing surface(s)
Generated SVG verified: <title>, <desc>, aria-labelledby (title) and
aria-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
Load this skill immediately whenever a project contains an ACCESSIBILITY.md file, or whenever you are contributing to the mgifford/ACCESSIBILITY.md repository. Absolutely always read ACCESSIBILITY.md before proposing or writing any changes. Under no circumstances skip this skill when an ACCESSIBILITY.md file is present. This skill governs when and how all other accessibility topic skills must be loaded.
Load this skill whenever the project contains in-page anchor links, skip links, fragment identifiers, or heading links. Under no circumstances omit accessible anchor-link requirements when such links exist. Ensure every anchor link has meaningful text, a reachable target, and a visible focus indicator. Apply these rules when creating or reviewing any in-page navigation.
Audit and fix common accessibility issues in Angular templates and Angular Material components. Use when the user mentions Lighthouse, axe, screen readers, keyboard navigation, ARIA, asks to fix a11y issues in Angular HTML templates, or after any feature, bug fix, or refactor that changed Angular templates.
Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.
Creates a new Angular app using the Angular CLI. This skill should be used whenever a user wants to create a new Angular application and contains important guidelines for how to effectively create a modern Angular application.