Accessibility — table stakes, not nice-to-have
📖 Walk me through it — plain English
Accessibility (often shortened to a11y — the "11" is the eleven letters between the "a" and the "y") just means: can people who don't use a screen the way you do still use your website? That includes people who navigate with only a keyboard (no mouse), people who can't see the screen and rely on a screen reader (software that reads the page aloud, line by line, and lets a blind or low-vision user move through it with the keyboard), and people with low vision who need high contrast. This lesson's point is that interviewers expect this as a baseline, not as expert work. You don't need to be a specialist — you need to use the right HTML element, give every control a readable name, and make sure everything works with the keyboard.
An everyday analogy: think of a well-designed public building. It doesn't only have stairs — it has ramps, an elevator, braille on the signs, and doors wide enough for a wheelchair. None of that is "extra fanciness"; it's just how you build a place everyone can enter. Bad accessibility is like a shop with one step at the entrance and no ramp: most people walk in fine and never notice, but you've quietly locked out everyone who can't take that step. Good HTML is the ramp that's already built into the building's frame.
Three reasons it is worth doing, beyond being the right thing: (1) It is the law in many places. Public-facing sites have been sued under the Americans with Disabilities Act (US) and similar rules elsewhere; "we forgot about blind users" is not a defense. (2) It helps SEO. The same structure a screen reader relies on — real headings, descriptive link text, alt on images — is exactly what a search engine's crawler reads to understand and rank your page. (3) It helps everyone. Captions help people in a loud room; good contrast helps anyone in bright sunlight; keyboard support helps power users. Accessible design is usually just good design.
Here is how to approach it, in the order the lesson lists the ideas — roughly the order of "biggest win for least effort":
- Use the real element (semantic HTML). "Semantic" means the tag's name describes what it is, not just how it looks. Write
<button>, not a<div>you attached a click to. A<div>is a generic empty box with no built-in meaning; a<button>comes with keyboard support and announces itself as "button" to a screen reader for free. ARIA (Accessible Rich Internet Applications — a set of extra HTML attributes that describe a control to assistive technology without changing how it looks) is the patch you reach for only when no real element fits. - Make it work with the keyboard. Keyboard navigation means operating the whole page with no mouse. Pressing Tab moves focus (the invisible "you are here" cursor that decides which control receives your typing) from one control to the next, in the order they appear in the HTML — that order is called the focus order. Every clickable thing must be reachable by Tab and activatable with Enter or Space. If you built a custom control out of a plain element, add
tabindex="0"(the tabindex attribute controls whether and where Tab stops;0means "put this in the normal focus order") plus your own key handlers. - Keep focus visible. The browser draws a ring (the
outline) around whatever Tab has landed on. Don't delete it — if you do, keyboard users can't see where they are. If you dislike the default ring, replace it with your own:focus-visiblestyle. - Label every input. A text box needs a real
<label>(or anaria-labelattribute — an ARIA label is a string that gives a control its spoken name when there's no visible text to use) so the screen reader can say what to type. Placeholder text — the gray hint inside the box — does not count, because it vanishes the moment you start typing. - Check color contrast. The contrast ratio is a number that measures how different two colors are in brightness, from 1:1 (identical, invisible) up to 21:1 (pure black on pure white). Text must stand out enough from its background. The WCAG (Web Content Accessibility Guidelines, the standard rulebook everyone cites) "AA" level wants a ratio of at least 4.5 to 1 for normal text (3 to 1 for large text). Light gray text on a white background is the classic fail.
- Announce meaningful changes. When content updates without a page reload (like "3 results found"), a sighted user sees it but a screen reader won't notice. Wrap that message in a region marked
aria-live="polite"and the screen reader reads the change out loud. Only do this for things that matter — don't spam. - Give images alt text. Alt text (
alt="...") is the words a screen reader speaks in place of an image that it cannot see. Describe what it shows. If the image is purely decorative, use an emptyalt=""so it's skipped entirely. Missing alt text is one of the most commonly flagged problems. - Sanity-check with tools. Run the axe browser extension (it scans the page and lists issues), try navigating with only the keyboard, and turn on a screen reader — VoiceOver on Mac or NVDA on Windows — for a 30-second listen.
Why this is enough: most accessibility "wins" come not from clever code but from not throwing away what HTML already gives you. A real <button>, a real <label>, and a visible focus ring already cover keyboard use and screen readers. The remaining items — contrast, alt text, live regions — are quick checks a tool can flag in seconds. So in an interview, the move is simple: reach for the correct element first, name your controls, never kill focus, and mention you'd run axe and a keyboard pass to confirm.
Frontend interviewers increasingly ding candidates who build inaccessible UIs. The bar isn't "be a specialist" — it's "use the right element, give it a name, make it work with a keyboard."
A vocabulary you can rely on
Accessibility has a lot of jargon, but almost all of it boils down to a handful of plain ideas. Here is the whole vocabulary in one place so nothing below is a mystery:
- a11y — shorthand for "accessibility" (a + 11 letters + y). Designing so people with disabilities can use your site.
- Semantic HTML — choosing tags by meaning:
<button>for an action,<nav>for navigation,<h1>for the page's main heading. The opposite is wrapping everything in meaningless<div>and<span>boxes. - Screen reader — software (VoiceOver, NVDA, JAWS) that speaks the page aloud and lets a non-sighted user move through it by keyboard. It builds its narration from your HTML, so good HTML = a usable page.
- ARIA role — an attribute (
role="...") that tells assistive tech what a thing is when the tag itself doesn't say it: e.g.role="button"makes a<div>announce as a button. Native elements already carry an implicit role, which is why you rarely need this. - ARIA label — an attribute (
aria-label="Close"oraria-labelledby="id") that supplies the spoken name of a control when there is no visible text — for example an icon-only "X" button. - Alt text — the
altattribute on an<img>; the text a screen reader reads instead of the picture. - Keyboard navigation / focus order — using the page with Tab/Shift+Tab/Enter/Space/arrows. "Focus order" is the sequence Tab visits controls in; by default it follows the order of the HTML source.
- Focus — which single element is currently "active" and receiving keystrokes. The visible ring around it is the focus indicator.
- Focus trap — deliberately keeping focus inside a region so Tab can't escape it. Correct and necessary inside an open modal dialog (so you can't tab into the hidden page behind it); a bug everywhere else (if Tab gets stuck in a widget, a keyboard user is locked out).
- Contrast ratio — a 1:1-to-21:1 measure of how distinguishable two colors are. WCAG AA wants 4.5:1 for body text.
- WCAG — Web Content Accessibility Guidelines, the international standard, organized into levels A, AA (the common legal target), and AAA (strictest).
- Landmark — a big structural region a screen reader can jump between:
<header>,<nav>,<main>,<aside>,<footer>. They give the page a table-of-contents so users don't have to wade through everything linearly. - tabindex — attribute that adjusts focusability:
tabindex="0"adds an element to the normal Tab order;tabindex="-1"makes it focusable only by script (not by Tab); a positive number jumps it ahead of others (almost always a mistake — avoid).
Before / after: the div-button vs the real button
This is the single most common a11y mistake, so let's see it concretely. A styled <div> can look identical to a button, but to a keyboard or screen-reader user it is invisible and dead — it isn't in the focus order, Enter and Space do nothing, and it announces as nothing:
<!-- BEFORE: looks like a button, isn't one -->
<div class="btn" onclick="save()">Save</div>
<!-- no Tab stop, no Enter/Space, screen reader hears plain "Save" text -->
The fix is not more code — it is less. Use the element built for the job. The browser hands you focusability, Enter/Space activation, and the spoken role "button" for free:
<!-- AFTER: the real element does everything for you -->
<button type="button" onclick="save()">Save</button>
<!-- in Tab order, fires on Enter/Space, announced as "Save, button" -->
If — and only if — you are forced to keep the <div> (say a design system that can't change yet), you must rebuild by hand everything the real button gave you: a role, a Tab stop, and key handlers.
<!-- LAST RESORT: a div pretending to be a button -->
<div class="btn" role="button" tabindex="0"
onclick="save()" onkeydown="if(event.key==='Enter'||event.key===' ')save()">Save</div>
Three attributes and a handler to reproduce what one tag did. That is why the next rule exists.
The first rule of ARIA
The first rule of ARIA: don't use ARIA. If a native HTML element with the meaning and behavior you need already exists, use it instead of repurposing a generic element and bolting on ARIA. <button> beats <div role="button">; <a href> beats <span role="link">; <input type="checkbox"> beats <div role="checkbox">. ARIA only changes what assistive tech announces — it adds zero behavior: no focus, no keyboard handling, no clicks. So role="button" on a <div> makes a screen reader say "button" while the thing still does nothing on Enter. Reach for ARIA only to fill a real gap that no native element covers (e.g. aria-live for dynamic announcements, or describing a complex custom widget).
Before / after: an image without alt text
A screen reader cannot see pixels. With no alt, many readers fall back to announcing the file name — useless noise like "chart underscore 4 final dot p-n-g":
<!-- BEFORE: no alt -->
<img src="chart_4_final.png">
<!-- AFTER: alt describes the meaning, not the pixels -->
<img src="chart_4_final.png" alt="Q3 revenue up 12% over Q2">
<!-- DECORATIVE: empty alt tells the reader to skip it entirely -->
<img src="swirl-divider.png" alt="">
Note the difference between missing alt and alt="". Missing means "I forgot" (reader guesses, badly). Empty means "I decided this is decoration" (reader stays silent). Both are valid HTML; only one is intentional.
Common pitfalls
- Removing the focus outline globally (
*:focus { outline: none }). Now nobody can tell where the keyboard is. Restyle with:focus-visibleinstead — never delete. - Treating placeholder as a label. It disappears the instant the user types and is announced unreliably. Always pair an input with a real
<label for="...">or anaria-label. - Positive
tabindexvalues (tabindex="3"). They override the natural focus order and quickly become an unmaintainable mess. Stick to0and-1and let the DOM order do the work. - Icon-only buttons with no name. A bare "🗑" or "✕" button announces as nothing. Add
aria-label="Delete"so it has a spoken name. - An accidental focus trap. A widget that swallows Tab and never lets it out locks keyboard users in. The only place a trap is correct is inside an open modal — and even then you must release it (return focus to the trigger) when the modal closes.
- Heading levels used for size. Don't pick
<h3>because it "looks right"; screen-reader users navigate by heading level, so skipping from<h1>to<h4>breaks the outline. Choose the level by structure, style with CSS. - Color as the only signal. "Required fields are red" excludes color-blind users. Add text or an icon too.
<button> not <div onClick>. <nav>, <main>, <label>. Free keyboard + screen-reader behavior. ARIA is the patch when semantics don't exist.
Tab order follows DOM. Every interactive thing must be reachable + activatable with Enter/Space. Custom controls: tabindex="0" + key handlers.
Don't kill outline. Replace with a custom :focus-visible style. Invisible focus = unusable for keyboard users.
Every form input needs a <label> (or aria-label). Placeholder is NOT a label — it disappears on focus.
WCAG AA: 4.5:1 for normal text, 3:1 for large. Devtools and axe will check it. Light gray on white is the classic failure.
aria-live="polite" for status updates ("3 results"). Don't announce noise — only meaningful changes.
<img alt="...">. Decorative? alt="". Missing alt is one of the most flagged a11y issues.
axe-core extension, keyboard-only navigation, VoiceOver (Mac) / NVDA (Windows) for a 30-second sanity check.
Takeaway: accessibility is mostly about not discarding what HTML already gives you. Reach for the real element first (semantic HTML), give every control a spoken name (label or aria-label), keep focus visible and in a sensible order, describe images with alt, hit WCAG AA contrast (4.5:1), and announce dynamic changes with aria-live. Remember the first rule of ARIA — use a native element instead — and confirm with axe plus a 30-second keyboard-and-screen-reader pass. It is the law, it helps SEO, and it helps everyone.
Go deeper (optional): the canonical references are the WCAG 2.1 quick-reference, the WAI-ARIA Authoring Practices (patterns for dialogs, menus, comboboxes), and MDN's accessibility section. The axe-core extension and the browser's built-in Lighthouse audit both surface concrete issues with fixes.