Accessibility

Same five bugs in every audit: div buttons, missing labels, broken headings

Tab through your product. Can you see focus? Can you open and close a dialog without a mouse? ## Semantic HTML before ARIA `<button>` has role, keyboard handling, and form-submit built in. A `<div role="button" tabIndex={0}>` reproduces all of that worse. - **Clickable `<div>`.** Use `<button>`. If it navigates, use `<a href>`. - **Custom dropdowns.** Use `<details>` / `<summary>`. - **Custom checkboxes.** Style `<input type="checkbox">`. Don't replace it. - **`<div role="navigation">`.** Use `<nav>`. - **Heading text in `<div class="title">`.** Use `<h1>`-`<h3>`. ARIA is for tab panels, live regions, custom comboboxes. Reach for it second. ## Icon buttons need `aria-label` ```tsx <button aria-label="Delete" onClick={handleDelete}> <TrashIcon aria-hidden="true" /> </button> ``` - **Visible text wins.** Don't add `aria-label` if text already exists. - **Decorative icons get `aria-hidden`.** - **Be specific.** "Delete this comment" beats "Delete." - **Never contradict.** `aria-label="Cancel"` on a Submit button is a bug. ## Skip links ```html <a href="#main" class="skip-link">Skip to main content</a> <!-- ...navigation... --> <main id="main">...</main> ``` ```css .skip-link { position: absolute; left: -9999px; } .skip-link:focus { left: 1rem; top: 1rem; z-index: 9999; } ``` ## Heading hierarchy - **One `<h1>` per page.** - **Never skip levels.** `<h1>` then `<h3>` breaks the outline. - **Headings describe sections.** "Billing history," not "Section 1." - **Don't use headings for styling.** Use CSS for big bold text. ## Contrast WCAG: **4.5:1** body text, **3:1** large text and UI elements. Never rely on colour alone: - **Error fields:** colour + icon + label + role. - **Required fields:** colour + asterisk + SR-only text. - **Active tab:** colour + underline or weight change. ## `:focus-visible` Never apply `outline: none` without a replacement. ```css :focus-visible { outline: 2px solid var(--focus-color); outline-offset: 2px; } ``` ## Common mistakes - **Click handler on a `<div>`.** Mouse-only. Use `<button>`. - **`outline: none` with no replacement.** Keyboard users are blind. - **Skip link that CSS hid from focus.** Test by tabbing from page load. - **`aria-label` contradicting visible text.** Confuses everyone. - **`tabIndex="-1"` everywhere.** Removes from tab order. Use only for programmatic focus. - **`autocomplete="off"` on passwords.** Breaks password managers.