Skip to main content

Publishing

Accessibility

WCAG for docs — keyboard navigation, screen readers, colour contrast, alt text, focus management. The accessibility patterns that make docs usable for everyone AND easier for LLMs to parse.

Docs are the part of your product most likely to be read by someone who can't see the screen, can't use a mouse, or has a cognitive load budget you don't know about. WCAG 2.2 AA is the baseline every docs site should clear. Most of it is cheap to get right on day one and expensive to retrofit later.

This guide covers the accessibility patterns specific to docs. For the WCAG 2.2 AA full reference, see the W3C spec.

The big four

Keyboard navigation

Every interactive thing reachable + operable with Tab / Shift+Tab / Enter / Space. No keyboard trap. Focus outline always visible.

Screen reader compatibility

Structured headings, descriptive link text, alt text on images, ARIA labels on icon-only buttons. The page makes sense narrated aloud.

Colour + contrast

4.5:1 contrast for body text, 3:1 for large text + UI. Never rely on colour alone to convey meaning (icons + text labels).

Reading order + language

DOM order matches visual order. <html lang="en"> set. Plain language, expanded acronyms on first use, no jargon without definition.

What NookDocs ships accessibility-wise

Out-of-the-box behaviours every tenant gets:

  • Skip-to-main-content link at the top of every page. Hidden until focused; press Tab once to jump past the nav.

  • Semantic HTML<main>, <nav>, <article>, <header>, <footer> wherever appropriate. Screen readers use these as landmarks.

  • Focus outlines always visible (CSS outline not overridden to none).

  • <html lang="..."> from the tenant's language config or default en.

  • Theme tokens for contrast — every theme's light + dark palette hits WCAG AA minimum on body text.

  • Descriptive page titles<title> per page so screen-reader users hear where they are.

What's on you as the author:

  • Writing alt text for images you add.

  • Keeping heading hierarchy clean (see style and tone).

  • Not overriding link colours to match paragraph colour.

  • Not inventing custom interactive components that lack keyboard handlers.

Keyboard navigation

Every interactive element must be reachable with the keyboard:

Tab order follows visual order

DOM order = visual order = keyboard order. If a sidebar visually comes before the main content, it should come first in the DOM. NookDocs layouts enforce this.

Every interactive element has a visible focus indicator

A blue outline, a background shift, a ring — whatever your theme uses, it must be visible against both light and dark backgrounds. Don't outline: none without replacing with :focus-visible { box-shadow: ... }.

Enter and Space activate buttons

<button> elements handle both natively. Custom components built with <div onClick> don't — avoid them, or add onKeyDown + role="button" + tabindex="0".

Escape closes overlays

Search modal, contextual menu, mobile drawer — all dismissable with Escape. NookDocs's built-in components already handle this.

Test: unplug your mouse, navigate every page by keyboard. If you can't reach something, can't see where focus is, or get stuck — fix it.

Screen reader compatibility

Screen readers (VoiceOver, JAWS, NVDA) narrate the page aloud. They rely on structure, not visuals.

Headings as landmarks

Screen reader users navigate by heading — press H in JAWS/NVDA to jump heading by heading. Clean hierarchy matters more than for sighted readers:

  • One H1 per page (the page title).

  • Don't skip levels (no H4 directly after H1).

  • Use headings for structural sections, not for visual sizing.

Alt text for images

Every <Frame> / <Image> needs an alt attribute. Rules:

  • Describe the content relevant to the surrounding text. For a screenshot of a dashboard showing analytics: alt="Analytics dashboard showing 1200 daily page views and a search bar at the top".

  • Decorative images get alt="" (empty, not missing). Screen readers skip over them.

  • Don't repeat surrounding text. If the caption says "Analytics dashboard with page views", the alt text can be shorter: alt="Dashboard UI".

  • Avoid "image of" / "picture of" — the screen reader already announces "image".

<Frame caption="The Custom Domains panel after adding docs.acme.com">
  ![Dashboard panel listing docs.acme.com as verified with a green check](/images/custom-domain-verified.png)
</Frame>

Descriptive link text

Screen reader users pull up a list of all links with Insert+F7. If every link says "click here" or "read more", the list is useless.

❌ To add a custom domain, [click here](/deploy/custom-domain).
✅ Add a custom domain in the [deploy guide](/deploy/custom-domain).
✅ For DNS record specifics, see [custom domain setup](/deploy/custom-domain).

ARIA labels on icon-only buttons

Buttons that render only an icon (no text) need aria-label:

<button aria-label="Close search">
  <XIcon />
</button>

NookDocs's built-in interactive components handle this — the danger is when you build custom widgets. Always add an aria-label if there's no visible text.

Code blocks

Fenced code blocks render with role="region" and aria-label="Code example" (implicit from the <pre><code> elements). Screen readers announce the language when the fence has one: ​```bash announces "bash code example".

Multi-block <CodeGroup> tabs have proper ARIA — screen reader users hear "tab 1 of 3, cURL" and can arrow between tabs.

Colour + contrast

Text contrast thresholds

WCAG 2.2 AA minimums:

Text sizeMinimum contrast
Body text (< 18pt)4.5:1 against background
Large text (≥ 18pt or ≥ 14pt bold)3:1
UI components (buttons, focus outline, borders of interactive things)3:1

Tools:

  • Browser DevTools → Inspect an element → "Contrast" in the Colours panel. Works in Chrome + Firefox + Safari.

  • WebAIM Contrast Checker — paste hex values.

  • Stark — Figma / browser plugin, real-time checks.

Every NookDocs theme ships palettes that meet WCAG AA on --docs-fg against --docs-bg. When overriding via colors.primary / background.*, test the combination before shipping.

Never rely on colour alone

Red/green distinctions fail for ~8% of men. Always pair colour with an icon or label:

❌ Colour-only
<Badge variant="success">Active</Badge>
<Badge variant="danger">Failed</Badge>

✅ Colour + icon
<Badge variant="success"><CheckIcon /> Active</Badge>
<Badge variant="danger"><XIcon /> Failed</Badge>

The text label alone usually suffices; icons reinforce for scanning.

Dark mode

Auto-adaptive by default via prefers-color-scheme. Manual toggle via the theme button in the header. The <Visibility> component's agent/human split doesn't interact with dark mode — both variants render through both palettes.

Don't override --docs-fg-dark / --docs-fg-muted-dark without re-testing contrast.

Reading order + language

Reading order

DOM order = what screen readers narrate. If your CSS re-orders elements visually (flexbox order, grid areas, absolute positioning), screen reader users hear the original DOM order, not the visual one.

NookDocs layouts keep DOM == visual. When writing MDX, structure top-to-bottom in the order you want it read.

Language attribute

<html lang="en"> set on every page automatically from tenant language config. Multi-language tenants use the language's slug. Critical for:

  • Screen reader pronunciation (reads English text with English phonemes)

  • Automatic translation tools

  • Search engine indexing

If a specific word or phrase is in a different language, wrap it:

The Japanese word <span lang="ja">ドキュメント</span> means "document".

Plain language

Technical writing can be precise without being jargon-dense. Every acronym defined on first use. Every domain-specific term linked to a glossary entry or explained in-line.

Flesch-Kincaid reading-ease score of 60+ is a good target for docs — roughly 8th-grade reading level. Tools:

  • Hemingway Editor — pasteable

  • VS Code extension tammersaleh.write-good — inline

  • Your LLM of choice — "score this passage for reading ease"

Motion + animation

WCAG 2.3 AAA: respect prefers-reduced-motion. Users with vestibular disorders can literally be nauseated by decorative parallax.

NookDocs's built-in components honour the preference — Framer Motion animations respect prefers-reduced-motion: reduce. When adding custom motion:

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

Good default: turn motion OFF when the user asks, turn it on when they don't.

Forms + inputs

(Less relevant for docs, but feedback widgets + search inputs apply.)

  • Every <input> has a <label for="..."> or aria-label.

  • Required fields marked with aria-required="true" + visible indicator (asterisk, the word "required").

  • Error messages have role="alert" or aria-live="polite" so screen readers announce them.

  • Don't validate on every keystroke — only on blur or submit. Frustrating announcements.

Testing protocol

Weekly, on a representative page:

Lighthouse accessibility audit

Chrome DevTools → Lighthouse → Accessibility category. Target: 95+. Covers 30-40% of WCAG via automated checks.

Keyboard-only navigation

Unplug your mouse. Navigate the page. Can you reach every link, button, toggle? Is focus always visible?

Screen reader spot-check

macOS: Cmd+F5 to enable VoiceOver, read the page. Windows: NVDA (free) or JAWS. Listen for 2 minutes. Does the page make sense narrated?

Contrast check

DevTools → Inspect any text → Contrast ratio. Target: 4.5:1 body, 3:1 UI.

prefers-reduced-motion

macOS: System Preferences → Accessibility → Display → Reduce motion. Visit the page. Animations should be ~0ms.

Common accessibility mistakes

Related

Was this page helpful?

Last updated August 7, 2026