Web Accessibility (a11y)
Designing and building a site so people using assistive technology, like screen readers or keyboard-only navigation, can actually use it.
What is it?
Not everyone browses the web the same way. Some people can't see a screen at all and rely on software that reads the page aloud. Some people can't use a mouse and navigate entirely with a keyboard. Some people have low vision and need large, high-contrast text. A site that only works if you can see a screen clearly and click precisely with a mouse simply doesn't work for a meaningful number of people.
Accessibility, often abbreviated a11y (the 11 stands for the number of letters skipped between the "a" and the "y"), is the practice of building sites that work for people using assistive technology, not just a typical mouse-and-monitor setup. This isn't a separate feature bolted on afterward — it's mostly about doing the basics correctly: using real, semantic HTML elements instead of generic ones styled to look the part, giving every image a meaningful text description (alt text) for people who can't see it, and making sure every interactive element can be reached and operated using only a keyboard.
A big piece of this is focus management — making sure that as a keyboard user tabs through a page, the currently focused element is clearly visible, follows a sensible order, and that opening things like a modal dialog moves focus into it (and traps it there) so a keyboard user isn't left tabbing through content hidden behind it.
Explain like I'm 10
It's like designing a building with ramps and clear signage alongside stairs — most people might not notice they're there, but for someone using a wheelchair or who can't read small print, they're the difference between being able to get in the door at all.
Examples
Meaningful alt text
<!-- Bad: unhelpful or missing -->
<img src="chart.png" alt="image">
<!-- Good: describes the actual content -->
<img src="chart.png" alt="Bar chart showing sales rising 20% from January to March">A screen reader announces the alt text in place of the image. 'image' tells a blind user nothing useful, while a real description lets them understand what the chart actually shows.
Keyboard-reachable custom controls
<!-- Not focusable or announced as a button by default -->
<div onclick="submitForm()">Submit</div>
<!-- Reachable by keyboard, announced correctly by screen readers -->
<button onclick="submitForm()">Submit</button>A div with a click handler is invisible to keyboard navigation and screen readers by default — it's just a generic block of text as far as assistive technology is concerned. A real button element is automatically focusable, triggerable with the keyboard, and announced as a button.
How it works
Assistive technology, like a screen reader, doesn't see rendered pixels — it reads the underlying HTML structure (often via the DOM) and uses each element's role, name, and state to describe the page out loud or via braille output. Semantic elements come with these roles already built in (a button announces itself as "button" and responds to keyboard activation automatically); generic elements styled to merely look like a button carry none of that information unless it's added back manually.
Why does it exist?
Accessibility work exists because the web is meant to be usable by everyone, not only people who can see a screen clearly and operate a mouse precisely. Beyond that, in many places it's also a legal requirement for certain kinds of sites. Practically, accessible practices — clear structure, sufficient contrast, keyboard support — also tend to make a site better for everyone, not just people using assistive technology.
When to use it
Accessibility considerations belong in every project from the start, not bolted on at the end — using semantic HTML, writing real alt text, and testing keyboard navigation cost very little when done as you build, and cost far more to retrofit later.
When not to use it
There's essentially no valid case for skipping accessibility on a public-facing site. The only reasonable trade-off is depth: a small personal project might not warrant a full accessibility audit, but even then, the basics (semantic tags, alt text, keyboard support) cost little and help everyone.
Common mistakes
Using generic elements styled to look interactive instead of real buttons or links, breaking keyboard and screen-reader support.
Writing unhelpful alt text like 'image' or 'photo1.jpg' instead of describing what the image actually conveys.
Trapping keyboard focus nowhere (or everywhere) — forgetting to move focus into a newly opened dialog, or forgetting to let focus escape it when it closes.
Practice exercises
- Easy:
Add meaningful alt text to three images on a sample page, describing what each one actually conveys.
- Medium:
Take a page and try navigating it using only the Tab and Enter keys. Note every interactive element you couldn't reach or activate.
- Hard:
Rebuild a custom dropdown menu made of styled divs using proper semantic elements and keyboard support, and verify it works with Tab, Enter, and Escape.
Interview questions
What does web accessibility mean?
Designing and building sites so people using assistive technology, such as screen readers or keyboard-only navigation, can perceive, understand, and use them.
Why does alt text matter, and what makes it good?
It's what a screen reader announces in place of an image, so it matters because it's often the only way a non-sighted user learns what the image conveys. Good alt text describes the actual content or purpose of the image rather than being generic or missing.
Why is using a real <button> element better than a styled <div> for something clickable?
A real button is automatically focusable, keyboard-activatable, and announced correctly by screen readers, while a div carries none of that behavior unless it's manually reimplemented.
What does ARIA stand for, and what's the 'first rule of ARIA'?
ARIA stands for Accessible Rich Internet Applications — a set of HTML attributes that describe roles, states, and properties to assistive technology. The first rule of ARIA is: if a native HTML element or attribute already provides the semantics and behavior you need, use that instead of recreating it with ARIA on a generic element, since native elements come with correct behavior built in and ARIA alone only adds semantics, not behavior.
What's the difference between `aria-label` and `aria-labelledby`?
aria-label provides an accessible name directly as a string value on the attribute itself. aria-labelledby instead points to the id of another element already on the page, and its text content is used as the accessible name — useful when the label text is already visible elsewhere and shouldn't be duplicated.
What does `aria-hidden="true"` do, and what's a common mistake with it?
It removes an element (and its descendants) from the accessibility tree, so screen readers skip over it entirely as if it didn't exist. A common mistake is applying it to an element that's still visually visible and focusable — a screen reader user's focus can land on a control that's been hidden from being announced, which is confusing and effectively broken.
What is a 'landmark region', and why does it matter for accessibility?
It's a semantic sectioning element like <nav>, <main>, <header>, or <aside> (or an equivalent ARIA landmark role) that marks a major region of the page. Screen reader users commonly navigate by jumping directly between landmarks instead of reading the whole page top to bottom, so their presence lets a user quickly get to the content they actually want.
What's the difference between `tabindex="0"`, `tabindex="-1"`, and a positive `tabindex` value?
tabindex="0" inserts the element into the natural tab order at the point matching the DOM. tabindex="-1" makes it programmatically focusable (via JavaScript, e.g. after opening a dialog) but skips it in normal Tab-key navigation. A positive value forces it earlier in tab order than 0, which is generally discouraged since it creates a custom order that's easy to get out of sync with the visual layout and hard to maintain.
A custom dropdown is built from a `<div>` with `tabindex="0"` but no keyboard event handlers. What happens when a keyboard user tabs to it and presses Enter?
Nothing — tabindex="0" only makes the element reachable by Tab, it doesn't make it activatable. A native <button> responds to Enter/Space automatically, but a plain div requires JavaScript to explicitly listen for those key presses and trigger the equivalent action; without that, the div is a dead end for keyboard users.
Why is focus trapping necessary in a modal dialog?
Without it, Tab can move focus out of the visible dialog and onto content underneath it that's supposed to be inaccessible while the modal is open — a keyboard user ends up tabbing through hidden page content they can't see, with no clear way back into the dialog. Trapping keeps Tab cycling only among the dialog's own focusable elements until it's closed.
What contrast ratio does WCAG's AA level require for normal text versus large text?
At least 4.5:1 for normal-sized text, and a lower 3:1 for large text (roughly 18pt/24px regular weight or 14pt/18.66px bold and larger), since larger text is inherently easier to distinguish from its background even at lower contrast.
Why might you use a 'visually-hidden' CSS technique instead of `display: none` for some content?
display: none (and visibility: hidden) removes content from the accessibility tree as well as visually, so a screen reader skips it too. A visually-hidden class (clipping the element to a 1px box, off-screen, without display:none) keeps it available to assistive technology while hiding it from sighted users — used for things like skip links or extra context meant only for screen readers.
What is a 'skip link', and what problem does it solve?
It's a link, usually the first focusable element on the page, that jumps straight to the main content, bypassing repeated navigation menus. Without it, a keyboard or screen reader user has to tab through the same nav links on every single page before reaching the actual content.
Why is removing the default focus outline with `outline: none` a common accessibility trap?
The focus outline is how a keyboard user sees which element is currently active. Removing it without providing any visible replacement style (like a custom box-shadow or border on :focus-visible) leaves keyboard users with no way to tell where they are on the page, even though the interaction still technically works.
What does a `<label>` element's `for` attribute do, and why does it matter beyond just sighted mouse users?
It associates the label with a specific form control by id, which does two things: clicking anywhere on the label text also focuses/activates the input (a bigger, easier click target for anyone with limited motor precision), and a screen reader announces the label text together with the input when it receives focus, rather than announcing an unlabeled field.
What does the `role` attribute do when you're stuck using a non-semantic element for some custom widget?
It tells assistive technology what kind of control the element represents (e.g. role="button", role="tablist"), so it's announced correctly. It only communicates semantics, though — it doesn't add any of the native keyboard behavior or focusability a real element would have, so those still need to be implemented manually alongside it.
What is the accessibility tree, and how does it relate to the DOM?
It's a separate tree, derived from the DOM, that represents each element's accessible role, name, state, and value — the actual structure assistive technology like screen readers consumes. Elements or attributes that are purely presentational (or explicitly hidden via aria-hidden) can be present in the DOM but omitted from the accessibility tree, and semantics added via ARIA can change how a node appears there without changing the DOM at all.
A form shows an invalid input by giving it a red border and nothing else — what's the accessibility problem, and how would you fix it?
Color alone doesn't convey the error to colorblind users or anyone using a screen reader, which can't perceive a border color change at all. A fix pairs the visual indicator with a text error message associated to the field via aria-describedby, and marks the field with aria-invalid="true" so assistive technology announces the invalid state explicitly.
A screen reader announces a form field's error message twice — what's a likely cause?
The same error text is probably exposed to assistive technology through two separate mechanisms at once — for example, it's both visually rendered inside content referenced by aria-describedby and also announced separately via an aria-live region updating with the same message, so the user hears it announced from both paths.
What's the difference between `aria-live="polite"` and `aria-live="assertive"`?
polite waits until the screen reader finishes whatever it's currently announcing before reading the update, so it doesn't interrupt the user. assertive interrupts immediately, regardless of what's being read — reserved for urgent updates, since overusing it is disorienting.