Display mode set too late
display/init-missing
- 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
- low
- axe-core rule
display/init-missing
Why we flag this
The page can briefly render in the wrong mode, for example with animation, before the chosen calm mode applies.
data-display not set by a blocking script in <head>.
What the rule checks
Scope. Pages that use the convention: at least one figure[data-viz] or a [data-display-toggle].
Expectation. A best-practice violation at html when html[data-display] is never set, or is set only after the body started rendering (a script at the end of body), so the page can show the wrong mode first. A blocking script in head that sets it passes, whatever form the toggle takes. Pages without the convention are out of scope.
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, interaction.
Failing example
The check reports a violation here. Corpus case visual_display_never_set, element html. The page may contain further findings for other rules.
<!DOCTYPE html>
<!-- Display-mode convention (#653) used without ever setting
html[data-display], with text layers removed from assistive technology
in three more ways: the hidden attribute, inert, and aria-hidden added by
a script after load. -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Display modes: mode never set, text layers hidden</title>
<style>
body { color: #111111; background: #ffffff; }
</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>
<button type="button" data-display-toggle style="min-width: 44px; min-height: 44px">Switch display mode</button>
<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>Air quality</h1>
<figure id="f1" data-viz="diagram">
<svg data-viz-static width="300" height="80" aria-hidden="true"><rect width="300" height="80" fill="#4575b4"></rect></svg>
<div id="t-hidden-attr" data-viz-text hidden><p>Fine dust stayed below the limit all week.</p></div>
<figcaption>Fine dust this week</figcaption>
</figure>
<figure id="f2" data-viz="diagram">
<svg data-viz-static width="300" height="80" aria-hidden="true"><rect width="300" height="80" fill="#91bfdb"></rect></svg>
<div id="t-inert" data-viz-text inert><p>Ozone peaked on Thursday afternoon.</p></div>
<figcaption>Ozone this week</figcaption>
</figure>
<figure id="f3" data-viz="diagram">
<svg data-viz-static width="300" height="80" aria-hidden="true"><rect width="300" height="80" fill="#d73027"></rect></svg>
<div id="t-late" data-viz-text><p>Nitrogen dioxide fell by a third.</p></div>
<figcaption>Nitrogen dioxide this week</figcaption>
</figure>
<!-- Reachable text layer, visually hidden with the clip pattern: fine. -->
<figure id="f4" data-viz="diagram">
<svg data-viz-static width="300" height="80" aria-hidden="true"><rect width="300" height="80" fill="#fee090"></rect></svg>
<div id="t-ok" data-viz-text style="position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;"><p>Pollen counts were low.</p></div>
<figcaption>Pollen this week</figcaption>
</figure>
</main>
<footer><p>Footer text</p></footer>
<script>
window.addEventListener('load', function () {
document.getElementById('t-late').setAttribute('aria-hidden', 'true');
});
</script>
</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.