3D in the browser sells. A configurator you can spin, a product seen from every side, a scene that reacts to scrolling: that sticks. For a screen reader, nothing of it remains.
It reads your website and finds, where your elaborate WebGL experience sits, exactly one piece of information: canvas. No text, no structure, no controls. A black hole in the middle of the page.
The usual reflex is to drop 3D. That is the mistake. You do not have to choose between experience and accessibility. You have to build both, side by side.
Why the canvas is a black box
WebGL draws pixels onto a surface. It produces no semantics: no headings, no buttons, no focusable text. Assistive technology, however, works with exactly that. It reads the DOM tree, not the image.
Where a screen reader announces “Button, request a quote” for a real button, it finds nothing to announce at the canvas. The keyboard runs into the void, because nothing inside the canvas is focusable. And text you render into the 3D scene is no longer text, but colour. The problem is not that WebGL is bad. It simply delivers none of the information accessibility needs.
The principle: a second, invisible layer
The solution flips the problem around. Instead of making the graphics accessible, you build a real HTML structure in parallel to the 3D scene that offers the same actions. Every interactive object gets a real counterpart in the DOM: a <button>, an <a>, a focusable element with an aria-label. Screen reader and keyboard operate this layer, your Three.js logic reacts to it.
<!-- Visible: the 3D scene -->
<canvas id="scene" aria-hidden="true"></canvas>
<!-- Parallel: the accessible controls -->
<div class="scene-controls">
<button aria-label="Rotate model left" data-action="rotate-left"></button>
<button aria-label="Change colour to anthracite" data-action="color-anthracite"></button>
</div>
<!-- Announcing state changes -->
<p class="visually-hidden" aria-live="polite" id="scene-status"></p>
The canvas gets aria-hidden="true" so the screen reader does not stumble over an empty surface. The controls live in real elements that may sit visually in the right place, but are semantically complete. Through an aria-live region you announce what happens in the scene. Whoever sees, rotates the model with the mouse. Whoever does not, presses a button and hears the result. Same function, two paths.
Motion is the biggest lever, and the simplest
Before you think about screen readers, take care of motion. Auto-rotation, camera moves, parallax: for some people these are not nice details, but triggers for dizziness, nausea or, in the extreme, seizures. The solution is a setting operating systems have shipped for years - you only have to respect it.
const calm = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!calm) startAutoRotation(); // otherwise the scene stays still
Anyone who enabled “reduce motion” in their system gets a calm scene instead of an endless spin. In react-three-fiber, A11yUserPreferences from react-three-a11y takes this query off your hands. It is the point with the best effort-to-impact ratio: a few lines, covers WCAG 2.3.3 and 2.2.2, helps noticeably.
Keyboard, and a focus you can see
Once the scene is operable, it has to be so by keyboard. Every counterpart from the parallel layer belongs in the tab order, triggerable with Enter and Space. And the focus must be visible - not only in the DOM, but in the scene: when someone tabs to “Part A”, highlight Part A in the 3D model too, with an outline or a highlight. That keeps the visual and the semantic layer in sync. A focus only the browser knows, but nobody sees, helps no one.
The tools, a reality check
Three paths, and none is a free ride:
- react-three-a11y (pmndrs) for react-three-fiber: provides the
<A11y>wrapper, roles like Button, ToggleButton or Link, focus management and theA11yAnnouncerfor announcements. It builds the parallel layer largely for you. The catch: the last release is from 2022. It works, but you are not stepping onto an actively maintained foundation. - Babylon.js ships an HTML twin with its accessibility package: Babylon automatically generates a parallel DOM tree from the scene and GUI, including ARIA. Whoever already uses Babylon has the shortest path.
- Plain Three.js has nothing built in. Here you build the parallel layer yourself, as above. More work, full control.
No tool makes your scene compliant at the push of a button. They take mechanics off your hands. The conceptual work - which information must be accessible via which path - stays with you.
What the law actually requires
Since 28 June 2025, the European Accessibility Act applies across the EU and affects many B2C providers, from the online shop to the bookable service. The technical benchmark is EN 301 549, which at its core points to WCAG 2.1 level AA. In the US, Section 508 and ADA guidance converge on the same WCAG standard. For a 3D website that means:
- Every piece of information and every action that exists only in the 3D scene is also reachable without the scene.
- Everything is keyboard operable, the focus is visible.
- Motion can be stopped and respects
prefers-reduced-motion. - Text in the canvas has a real text equivalent.
- Contrast meets the AA thresholds, including for controls.
- There is an equivalent alternative wherever a part cannot be made fully accessible.
The fallback is not a defeat
Some 3D experiences you cannot make fully accessible without destroying them. That is no reason to skip it, and none to hide it. The clean way is an equivalent, non-visual alternative: a text description, a 2D view, a plain option list offering the same choices as the configurator. Accessibility does not demand that everyone takes the same path. It demands that everyone reaches the goal.
I build 3D web experiences that impress and still work for everyone. That is not a contradiction, but a question of architecture: the show in the canvas, the substance in the DOM. Whoever thinks both together from the start has nothing to retrofit later - and stands calm before any accessibility law.
FAQ
Can a WebGL website be accessible at all? +
Yes. Not the graphics become accessible, but a parallel HTML layer beside them, plus switchable motion and a fallback. The show stays in the canvas, the substance lives in the DOM.
Does my 3D website have to be accessible? +
If you offer consumers a shop, a booking or many digital services, very likely yes - under the European Accessibility Act since 28 June 2025 in the EU, and under Section 508 / ADA guidance in the US.
Is an alt text enough for the canvas? +
No. A static alt text describes an image. An interactive 3D experience needs operable counterparts, not a caption.
What is the most common mistake? +
Putting essential information only inside the scene, without a second path. And an auto-rotation that cannot be switched off.
Want to know more?
In a free intro call we discuss how you can use these topics for your company. Not a sales pitch, but an honest assessment.
Book a free intro call