skip to content

Accessibility Integration

Baking accessibility into shared elements once: WAI-ARIA pattern roles and states, per-widget keyboard contracts, shared focus utilities, required accessible names. One fix reaches every consumer.

part ofDesign systems & UX foundationsoverview, primer and where to startread it →
on this pageshow

questions

4

In a shared component library, how should an icon-only button component ensure every instance has an accessible name?

level: juniorimportance: must knowfreq 58%

answer

  1. make the wrong thing impossible
  2. no name, no button
  3. name the action, not the icon
  4. row context in the name
  5. Name, Role, Value at Level A

basics

~20 s

Make the label a required input the component cannot be created without, and feed it into the accessible name. It should name the action and its object, such as download invoice 1042, never the icon.

solid answer

~50 s

An icon-only button has no visible text, so nothing supplies its accessible name unless the author does — and WCAG 2.2 success criterion 4.1.2 Name, Role, Value (Level A) requires one. A library fixes this once for every consumer by making the label a **required input**: where the tooling can enforce it, the button cannot be created without one; where it cannot, the component fails loudly in development. The label becomes the accessible name, and can double as the hover hint. It should name the **action and its object** — `Download invoice 1042`, not `download icon` — because a list of twenty identical names in a table is useless. The library also refuses silent fallbacks such as the icon's file name. Where design allows, a visible text label is still better: visible text keeps the name maintained and helps people who never hear accessible names.

go deeper

for a junior

Recall that every icon-only button needs an accessible name naming its action, and that the library makes that name a required input.

for a middle

Explain how enforcement works at creation and in development, why fallbacks hide failures, and how a name distinguishes rows in a table.

for a senior

Show how you would find unnamed buttons across consuming apps, migrate them, and decide which icon-only actions should gain a visible label instead.

for a principal

Weigh strict enforcement that can break consumers' builds against softer warnings, and set the system rule that icon-only is an exception to justify.

## Why icon-only buttons are the classic gap Every interactive control needs an **accessible name** — the text assistive technology announces to identify it. A button with visible text usually gets its name from that text. An **icon-only button** has none, so unless its author supplies a name, a screen reader announces something like *button* and nothing more, and a voice-control user has nothing to say to activate it. This is not a nicety. Under WCAG 2.2, success criterion **4.1.2 Name, Role, Value** (Level A) requires that the name and role of every user interface component can be programmatically determined. A missing name on an icon button is one of the most common failures of it. ## Why the library is the right place to fix it In a small-business accounting product, the invoice table has three icon buttons per row — duplicate, download, archive — and the same icon buttons appear in bills, quotes and expense claims. If each product team must remember to name each instance, some will not. A library component that **cannot be used without a name** removes the decision from hundreds of call sites. | Approach | Where names come from | Typical outcome | |---|---|---| | Leave naming to consumers | each call site, if remembered | some buttons announce only *button* | | Optional label input | consumers who read the docs | better, still gaps | | Required label input | enforced at creation | every instance named | | Silent fallback to icon name | the icon's file name | named, but uselessly (*copy*, *arrow-down*) | ## How to make the label required 1. **Make it a required input.** Where the library's language or tooling can express required inputs, the button will not build without a label. 2. **Fail loudly in development** where it cannot: a clear warning naming the component and the fix, not a silent render. 3. **Feed the label into the accessible name** and, where the design wants it, into a hover or focus hint, so sighted and non-sighted users hear the same words. 4. **Refuse fallbacks.** No default name, no deriving it from the icon's file name; a wrong name is worse than an obvious gap because it passes a quick check. 5. **Apply the rule across the library.** Icon-only toggles, menu triggers and icon links carry the same requirement; one library-wide rule — *no interactive icon without a name* — beats fixing components one at a time. ## What a good name says The Authoring Practices naming guide asks for **brief, useful names** (Rule 5). For an icon button, that means: - **The action, not the picture.** *Duplicate invoice*, not *copy icon*. - **The object when there are many.** In a table, *Download invoice 1042* distinguishes rows; twenty buttons all called *Download* do not. - **No role words.** Assistive technology already announces *button*; *download button* says it twice. - **Consistency with any visible hint.** WCAG 2.2 success criterion **2.5.3 Label in Name** (Level A) requires that when a component has a visible text label, its accessible name contains that text, so a voice-control user can say what they see. - **Stable across states.** For a toggle such as *Mark as paid*, the Authoring Practices button pattern says the label must not change when the state changes; the library exposes the pressed state instead of swapping names. The library can help with the object part too: a row-action button can accept the row's identifying text and compose *Download invoice 1042* itself, so consumers pass data rather than hand-writing strings. ## When the right fix is a visible label The same naming guide's **Rule 2, Prefer Visible Text**, points out that names that exist only in code drift out of date when the design changes, and that visible labels help many people who never hear an accessible name. An icon that is not universally understood — *archive* versus *void* in accounting is a real ambiguity — is often better as an icon plus a word. The library should make that easy (a button with icon and text is the same component, not a new one) and treat icon-only as the exception it has to justify. ## The same rule on native mobile Native platforms have the same concept — every control exposes a label to the platform's screen reader and voice control — and the same failure. A cross-platform system states the rule once in the component spec (*icon-only buttons require a label naming the action*) and each platform's library enforces it in its own way.

  • A consumer passes the label 'Button' to satisfy the requirement. What can the library do?
    A required input guarantees presence, not quality. The library can warn in development on obviously useless values — the role word, the icon's own name, an empty or whitespace string — and its usage guidance should show good and bad names. Beyond that, review and manual testing catch the rest; no check can judge meaning.
  • Why is a silent fallback to the icon's name worse than no name at all?
    A missing name is an obvious defect that a quick automated check will flag. A fallback like 'arrow-down' produces a name, so the check passes, while the user still hears something meaningless. The failure moves from visible to hidden, which makes it last much longer.

saying these in an interview costs you the question

  • A screen reader can describe an icon by itself, so no name is needed.
  • The icon's file name is a reasonable default accessible name.
  • Every download button in a table can share the name 'Download'.
  • Adding the word 'button' to the name helps screen-reader users.
  • Naming is each product team's job, not the library's.
open as a page

In a component library, why provide one shared live-region announcer instead of letting each component create its own live region?

level: middleimportance: should knowfreq 38%

basics

~10 s

Live regions created on the fly are often not announced, and many regions talk over each other. One announcer mounted up front queues, deduplicates and throttles status messages, so every component announces reliably.

open as a page

In a component library, what keyboard contract should a tabs component implement per the WAI-ARIA Authoring Practices, and when should activation be manual?

level: middleimportance: should knowfreq 45%

basics

~20 s

Tab enters the list on the active tab and leaves it for the panel; arrow keys move between tabs and wrap. Activation follows focus only when panels appear without noticeable latency; otherwise Space or Enter activates.

open as a page

In an accounting product, a library date picker opened inside a record-payment dialog lets Tab escape to the page behind, and closing it loses focus. How should the library fix this?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Replace per-component traps with one shared focus-layer stack: only the top layer contains focus, everything beneath is inert, Escape closes one layer, and closing returns focus to the opener, or a logical fallback if it is gone.

open as a page