know.2nth.ai Design accessibility
design · Accessibility · Skill Leaf

Built in from commit one,
or almost impossible to retrofit.

Accessibility is not a feature you add after the design is done. It's a constraint you design within from the start. WCAG 2.2 AA is the baseline — not the aspirational target. Semantic HTML, keyboard navigation, colour contrast, and screen reader compatibility are table stakes, not bonus points.

Live WCAG 2.2 AA ARIA Keyboard nav Screen readers

The contract between your interface and every user.

WCAG 2.2 AA defines the success criteria. The headline numbers: 4.5:1 contrast ratio for normal text, 3:1 for large text and UI components. All functionality reachable via keyboard. No information conveyed by colour alone. Focus indicators visible. Error messages associated with their fields. These aren't edge cases — they affect anyone using the interface in bright sunlight, on a small screen, with one hand, or while distracted.

Semantic HTML is free accessibility. A <button> is focusable, clickable, and announced as a button by screen readers — with zero extra code. A <div onclick> does none of that without manual ARIA attributes, keyboard handlers, and role assignments. Start with the right element and you skip half the work.

The three things screen readers need

Role — what is this thing? (button, dialog, navigation, alert). Name — what is it called? (from visible text, aria-label, or aria-labelledby). State — what is it doing right now? (expanded, selected, disabled, checked). If any of these three is missing, the screen reader can't convey the element to the user.

Patterns that cover 90% of the work.

<!-- Skip link — lets keyboard users jump past the nav -->
<a href="#main" class="skip-link">Skip to main content</a>

<style>
  .skip-link {
    position: absolute; top: -40px; left: 0;
    background: var(--blue); color: white;
    padding: 8px 16px; z-index: 200;
    transition: top 0.2s;
  }
  .skip-link:focus { top: 0; }
</style>
<!-- Modal dialog with focus trap and ARIA -->
<div
  role="dialog"
  aria-modal="true"
  aria-labelledby="dialog-title"
  aria-describedby="dialog-desc"
>
  <h2 id="dialog-title">Delete account</h2>
  <p id="dialog-desc">This will permanently remove your data.</p>
  <button autofocus>Cancel</button>
  <button>Delete</button>
</div>

/* Focus trap — keep Tab cycling inside the modal */
function trapFocus(dialog) {
  const focusable = dialog.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const first = focusable[0];
  const last = focusable[focusable.length - 1];

  dialog.addEventListener('keydown', (e) => {
    if (e.key !== 'Tab') return;
    if (e.shiftKey && document.activeElement === first) {
      e.preventDefault(); last.focus();
    } else if (!e.shiftKey && document.activeElement === last) {
      e.preventDefault(); first.focus();
    }
  });
}
/* Respect reduced motion preference */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Visible focus indicator — don't remove outline, style it */
:focus-visible {
  outline: 2px solid var(--sky);
  outline-offset: 2px;
  border-radius: 2px;
}
Contrast requirementRatioApplies to
Normal text (under 18px / 14px bold)4.5:1Body copy, labels, links
Large text (18px+ / 14px+ bold)3:1Headings, large buttons
UI components and graphics3:1Icons, borders, focus rings
AAA enhanced (optional)7:1Maximum readability

The accessibility mistakes that ship to production.

Removing focus outlines for "aesthetics"

*:focus { outline: none; } is the single most common accessibility violation on the web. Style the outline instead. Use :focus-visible to only show it for keyboard users.

ARIA as a first resort instead of last

The first rule of ARIA: don't use ARIA if a native HTML element does the job. <button> beats <div role="button"> every time. ARIA is a polyfill for semantics that HTML doesn't cover — dialogs, tabs, tree views — not a replacement for using the right element.

Testing with automated tools only

axe, Lighthouse, and WAVE catch about 30% of accessibility issues. They can't test whether a screen reader announces things in a sensible order, whether the tab sequence is logical, or whether the content makes sense without visual context. Manual testing with VoiceOver, NVDA, or TalkBack is required.

Colour as the only indicator

A red border on an error field means nothing to a colourblind user. Add an icon, a text label, or an aria-describedby error message. Never rely on colour alone to convey state.

Where to invest testing time.

Always test

  • Keyboard-only navigation through every user flow — tab, shift-tab, enter, escape, arrow keys.
  • Screen reader walkthrough of the primary happy path (VoiceOver on macOS, NVDA on Windows).
  • Colour contrast on every text-on-background combination using a tool like WebAIM's contrast checker.
  • Focus management after modal open/close, route changes, and dynamic content updates.

Where accessibility links in the tree.

Go deeper.