Skip to content

help.gevell.com β€” Redoc accessibility debt (RESOLVED)

Resolved 2026-09-11 by migrating the help center off Docusaurus/Redoc to Starlight. Redoc is no longer used anywhere; the API reference is now rendered by starlight-openapi, which emits native semantic markup (not Redoc’s canvas/table layout). All five violations below are gone β€” the whole built site, including /api/vpat-parse/..., passes the pa11y WCAG2AA CI gate (49/49 pages). See docs/admin/operations/user-docs-site.md for the current architecture. The detail below is retained as the rationale for the migration.

The one starlight-openapi a11y quirk found during migration β€” duplicate id="headers" on operation pages (request + response Headers) β€” is fixed in our own build by the dedupe-ids post-build integration (docs/user/src/integrations/dedupe-ids.mjs), not left as debt.


Five WCAG AA violations on /api/vpat-parse could not be fixed with CSS or Redocusaurus config alone β€” they required changes inside Redoc’s source code. Tracked here (now resolved by dropping Redoc entirely).

Audit job: https://audit.gevell.com/jobs/6ad9387b-23f0-4ac9-b8b0-b088ebba0d2b
Affected page: https://help.gevell.com/api/vpat-parse
Renderer: Redoc 2.4.0 via Redocusaurus 2.5.2


1. WCAG 2.1.1 / 2.1.2 β€” Keyboard trap and unreachable tabs (critical)

Occurrences: 12
Selectors: li#tab_r_2_0 through li#tab_r_2_11

Redoc renders HTTP response-code example tabs as <li role="tab"> elements using react-tabs. Two problems:

  • li#tab_r_2_0 traps Tab focus for 8+ consecutive keypresses (axe no-keyboard-trap)
  • li#tab_r_2_1 – li#tab_r_2_11 are not reachable via Tab at all (axe keyboard-reachable)

Root cause: react-tabs expects arrow-key navigation within the tablist (correct per ARIA), but the tab elements don’t expose a tabindex that lets Tab reach or leave the tablist reliably. Redoc may also be suppressing keydown events.

Fix required: In Redoc’s tab component, ensure exactly one tab has tabindex="0" (the selected tab) and all others have tabindex="-1", and that Tab moves focus out of the tablist to the associated tabpanel. File an issue or fork at https://github.com/Redocly/redoc.


2. WCAG 4.1.2 β€” Focusable content inside aria-hidden (serious)

Occurrences: 2
Selectors:

  • #/paths/~1health~1get > ... > .sc-fmBBaG.gNOWMI[aria-hidden="true"]
  • #/paths/~1api~1v1~1vpat-parse~1post > ... > .sc-fmBBaG.gNOWMI[aria-hidden="true"]

Redoc’s expand/collapse chevron icons are wrapped in a container with aria-hidden="true", but the container holds focusable children. Screen readers encounter elements that are hidden to AT but still accept focus, breaking the AT model.

Fix required: Add tabindex="-1" to all focusable descendants of aria-hidden containers inside Redoc’s expand/collapse button components, or restructure so the chevron icon itself is the aria-hidden element rather than its parent.


3. WCAG 1.3.1 β€” Heading level skip h2 β†’ h5 (moderate)

Occurrences: 1
Selector: h5.sc-iqshrI.sc-jQrzWy.dULaEs.kxkdMF

Redoc renders schema property names as <h5> inside a section whose parent heading is <h2>, skipping h3 and h4. The heading outline is non-contiguous.

Fix required: Change Redoc’s schema property heading level to h3 or h4, or make it a non-heading element styled to look like a heading with role="heading" aria-level="3". Upstream issue: the heading level is hardcoded in Redoc’s SchemaModel rendering.


Occurrences: 1
Selector: a.sc-dFtBrR.gsfHlu

Redoc renders a link to download the raw OpenAPI spec file. The visible link text is β€œDownload” with no additional context, which is non-descriptive when read in isolation by a screen reader navigating by links.

Fix required: Either add an aria-label (e.g. aria-label="Download OpenAPI spec") to Redoc’s download link component, or change the visible text. Could also be addressed via Redocusaurus component swizzling by overriding @theme/Redoc β€” see https://docusaurus.io/docs/swizzling.


5. WCAG 1.4.4 β€” Content clipped at 200% zoom (serious)

Occurrences: 1
Selector: div (top-level Redoc container)

At 200% browser zoom, a div inside the Redoc layout clips horizontally (scrollWidth=90px, clientWidth=34px), cutting off content without providing a scroll mechanism.

Fix required: The Redoc right-panel or schema table layout uses a fixed-width container that doesn’t respond to zoom. Needs overflow-x: auto or a responsive layout change in Redoc’s panel components. A CSS override scoped to .redocusaurus may partially help but the root constraint is in Redoc’s layout logic.


Background: Redocusaurus dark-mode CSS bug (resolved by CSS workaround)

Redocusaurus ≀ 2.5.2 generates dark-mode CSS under the selector html([data-theme='dark']) β€” note the parentheses β€” which is invalid CSS and never matches. The correct selector is html[data-theme='dark']. This caused 59 of the 60 colour-contrast failures in the audit (all in dark mode). The issue was worked around in commit 3482c2ae2 by adding explicit [data-theme='dark'] .redocusaurus overrides in docs/user/src/css/custom.css. The upstream bug should be reported to https://github.com/rohit-gohri/redocusaurus.