Visualisations visible in text mode
display/text-media-visible
- WCAG success criterion
- 2.2.2 (level A)
- Outcome class
- Automatic. An automated check that can report a confirmed violation.
- Area
- Accessibility, Navigation & Operation
- Default severity
- medium
- axe-core rule
display/text-media-visible
Why we flag this
Visitors who chose text mode still get graphics or moving content.
[data-viz-live]/[data-viz-static] or figure media visible with html[data-display=text].
What the rule checks
Scope. Pages rendered in text mode (html[data-display=text]) with figure[data-viz].
Expectation. A best-practice violation at the first rendered visualisation medium of a figure (static/live layer, canvas, svg, img, video, iframe, object, embed) that stays visible in text mode, outside the text layer. Hidden media pass; icons up to 32 x 32 px stay allowed (32 x 32 passes, 33 x 33 fails). Outside text mode the rule does not apply.
Source. BarrierLab display-mode convention draft v0 (barrierlab/plan/03), anchored to WCAG 2.2 SC 2.2.2; best practice
Detection: page; needs dom, computed_style, geometry.
Failing example
The check reports a violation here. Corpus case visual_display_text_mode_broken, element img#s2. The page may contain further findings for other rules.
<!DOCTYPE html>
<!-- Display-mode convention (#653), rendered in text mode, with the text-mode
mistakes real pages make: a text layer that stays visually hidden (clip
pattern) or transparent in text mode, and still images that are not
hidden. A 32x32 icon is allowed, 33x33 is not. -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Display modes: text mode that keeps pictures and hides text</title>
<script>document.documentElement.dataset.display = 'text';</script>
<style>
body { color: #111111; background: #ffffff; }
/* Forgot to reveal the text layer in text mode. */
#t1 { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
#t5 { opacity: 0; }
html[data-display="text"] #s1, html[data-display="text"] #s5 { display: none; }
</style>
</head>
<body>
<header>
<a href="#main" style="display: inline-block; min-width: 44px; min-height: 44px; line-height: 44px; padding: 0 8px">Skip to main content</a>
<label for="display-toggle">Display</label>
<select id="display-toggle" data-display-toggle style="min-width: 44px; min-height: 44px">
<option value="visual">Visual</option>
<option value="calm">Calm</option>
<option value="text" selected>Text</option>
</select>
<nav aria-label="Main"><a href="#main" aria-current="page" style="display: inline-block; min-width: 44px; min-height: 44px; line-height: 44px; padding: 0 8px">Overview</a></nav>
</header>
<main id="main">
<h1>River levels</h1>
<figure id="f1" data-viz="diagram">
<div id="s1" data-viz-static><svg width="300" height="120" aria-hidden="true"><rect width="300" height="120" fill="#4575b4"></rect></svg></div>
<div id="t1" data-viz-text><p>The river rose by 80 centimetres overnight.</p></div>
<figcaption>River level at the old bridge</figcaption>
</figure>
<figure id="f2" data-viz="diagram">
<img id="s2" data-viz-static width="300" height="120" alt="Bar diagram of rainfall"
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='120'%3E%3Crect width='300' height='120' fill='%23336699'/%3E%3C/svg%3E">
<div id="t2" data-viz-text><p>Rainfall was twice the monthly average.</p></div>
<figcaption>Rainfall in October</figcaption>
</figure>
<figure id="f3" data-viz="diagram">
<svg id="icon3" width="32" height="32" aria-hidden="true"><circle cx="16" cy="16" r="14" fill="#d73027"></circle></svg>
<div id="t3" data-viz-text><p>Flood warning level 2 is in force.</p></div>
<figcaption>Warning level</figcaption>
</figure>
<figure id="f4" data-viz="diagram">
<svg id="icon4" width="33" height="33" aria-hidden="true"><circle cx="16" cy="16" r="14" fill="#d73027"></circle></svg>
<div id="t4" data-viz-text><p>The ferry is suspended until further notice.</p></div>
<figcaption>Ferry status</figcaption>
</figure>
<figure id="f5" data-viz="diagram">
<div id="s5" data-viz-static><svg width="300" height="120" aria-hidden="true"><rect width="300" height="120" fill="#91bfdb"></rect></svg></div>
<div id="t5" data-viz-text><p>The water temperature is 11 degrees.</p></div>
<figcaption>Water temperature</figcaption>
</figure>
</main>
<footer><p>Footer text</p></footer>
</body>
</html>Passing example
The check passes here and reports nothing. Corpus case display_modes_conforming. The page may contain further findings for other rules.
<!DOCTYPE html>
<!-- Display-mode convention (#653) followed correctly, rendered in text mode:
data-display is set by a blocking script in <head>, the toggle exists,
the visualisation's media is hidden in text mode and its text layer is
visible. Expect no display/* finding. -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Display modes: conforming page</title>
<script>document.documentElement.dataset.display = 'text';</script>
<style>
html[data-display="text"] [data-viz-static],
html[data-display="text"] [data-viz-live] { display: none; }
html:not([data-display="text"]) [data-viz-text] {
position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0);
}
</style>
</head>
<body>
<header>
<nav aria-label="Display">
<label for="display-toggle">Display</label>
<select id="display-toggle" data-display-toggle>
<option value="visual">Visual</option>
<option value="calm">Calm</option>
<option value="text" selected>Text</option>
</select>
</nav>
</header>
<main>
<h1>Temperature since 1850</h1>
<figure id="f1" data-viz="chart">
<div data-viz-static>
<svg role="img" aria-label="Warming stripes" width="300" height="120" viewBox="0 0 300 120">
<rect width="150" height="120" fill="#4575b4"></rect>
<rect x="150" width="150" height="120" fill="#d73027"></rect>
</svg>
</div>
<div data-viz-text>
<p>The global mean surface temperature rose by about 1.3 degrees since 1850.</p>
<table>
<caption>Temperature anomaly</caption>
<tr><th scope="col">Year</th><th scope="col">Anomaly</th></tr>
<tr><td>1850</td><td>0.0</td></tr>
<tr><td>2025</td><td>1.3</td></tr>
</table>
<p>Source: example data.</p>
</div>
<figcaption>Global temperature anomaly</figcaption>
</figure>
</main>
</body>
</html>This page is generated from the rule catalogue and the rule contracts; see therule overview for how the outcome classes are derived.