---
name: accessibility
description: "Make interfaces usable by everyone, including keyboard and screen-reader users — semantic HTML, labelled controls, visible focus, enough contrast, alt text — tested by keyboard and audit. Use it when you build or change a page, form, dialog, menu, or any interactive component, and before launching a product that must meet WCAG or accessibility law."
license: MIT
metadata:
  author: "Gaitro"
  category: "design"
  copyright: "Copyright (c) 2026 Farnor"
  source: "https://gaitro.com/skills/accessibility"
---

# Accessibility

Accessible interfaces are better for everyone: they work with a keyboard, a screen reader, a small screen, or tired eyes. Most of it comes from using the right HTML element and labelling things properly.

## Steps

1. **Use the native element first.** `<button>` for actions, `<a href>` for navigation, `<label>` with `<input>` for fields, plus `<select>`, `<dialog>`, and `<details>`. They come with keyboard support, focus, and screen-reader roles built in. A clickable `<div>` has none of them.
2. **Give every control an accessible name.** Each input has a visible `<label for>` — placeholder text isn't a label. Icon-only buttons get an `aria-label`. Link text says where it goes ("See pricing", not "click here").
3. **Make everything work by keyboard.** Every interactive element is reachable with Tab in a logical order and works with Enter or Space. Menus and dialogs close with Escape; focus moves into a dialog when it opens and returns when it closes. Nothing traps focus.
4. **Keep focus visible.** Never remove the outline without a replacement — style `:focus-visible` with a clear ring.
5. **Meet contrast.** Text at least 4.5:1 against its background (3:1 for large text, and for icons and borders that carry meaning), in both light and dark themes. Never use color alone to signal meaning — add text or an icon to errors and states.
6. **Describe images.** Meaningful images get `alt` text that says what matters about them; decorative images get `alt=""`.
7. **Structure the page.** One `<h1>`, headings in order without skipping levels, landmarks (`<header>`, `<nav>`, `<main>`, `<footer>`), and a `lang` attribute on `<html>`.
8. **Announce what changes.** Form errors are tied to their field with `aria-describedby` and written in text; status messages that appear without a page load use `aria-live="polite"`.
9. **Use ARIA only to fill gaps.** If a native element does the job, use it. Wrong ARIA is worse than none.
10. **Respect people's settings.** Honour `prefers-reduced-motion`; text resizes to 200% without breaking the layout; nothing important is reachable only by hover.

## Verify

- Put the mouse away: complete the main task with only the keyboard, watching the focus ring the whole way.
- Run an automated audit — axe DevTools, Lighthouse, or `npx @axe-core/cli <url>` — and fix every violation. Automated tools catch only a share of issues, so the keyboard pass still matters.
- Spot-check the main flow with a screen reader (VoiceOver on macOS: Cmd+F5).

## Done when

- [ ] Every interactive element is a native control, or has a correct role, name, and keyboard behaviour
- [ ] Every form field has a visible label, and errors are announced in text
- [ ] The main task can be completed by keyboard alone, with focus always visible
- [ ] Contrast passes in light and dark themes
- [ ] The automated audit shows no violations

## Report back

What you checked (the keyboard pass, the audit tool and its result, the screen-reader spot check), what you fixed, and any remaining issues with the WCAG criterion and who they affect.

## Traps

- A `<div onClick>` instead of a `<button>`.
- Placeholder text as the only label.
- `outline: none` with no focus style to replace it.
- Treating a clean automated audit as proof that something is accessible.
