Rule
icon-button-accessible-name
Buttons whose only content is an icon need an aria-label (or visually hidden text).
- What it catches
- Buttons whose only content is an icon (from an icon library or icons module, or named like one:
XIcon,Trash2), with noaria-label,aria-labelledby,titleor visually hidden text. A child with text in its props (<IconMenu text=…>) or an unknown component makes it skip; a button passed as Base UI'srender, conditionally too, is judged by its own and its host's children, a render-prop child ({() => <Trash2 />}) by what it returns, and hidden buttons and a story'sargs.renderare skipped - Why it matters
- A button with only an icon is announced as just "button" to screen-reader users. It is the most common accessibility slip in real apps:
checkfound 11 in vercel/ai-chatbot and 105 in midday's dashboard. The fix guesses the label from the icon (Trash2→ "Delete").
Example
What check_ui returned for this code against the demo design system when the site was built, from version 0.6.0.
<Button variant="ghost" size="icon"> <Trash2 /></Button><Button aria-label="Delete" variant="ghost" size="icon"> <Trash2 /></Button>error1:2fix included
Icon-only <Button> has no accessible name. Add aria-label="Delete" describing the action, or visually hidden text.
How the fix is chosen
aria-label, guessed from the icon (Trash2 → "Delete").
Every finding in the example carries its fix as text edits, which the agent applies, and so does eslint --fix. The code after the fix is those edits, applied.
Options
Its default severity is "error". Set it to "off", "warn" or "error" in onsystem.config.json, or as onsystem/icon-button-accessible-name in the ESLint plugin.
{ "rules": { "icon-button-accessible-name": "warn" }}The config file covers the rest, including overrides for folders.
Suppressing a finding
When a finding is intended, a comment turns the rule off for the next line and says why after --. Checked when the site was built: the comment hides the finding on the line below it, and the others stay.
// onsystem-disable-next-line icon-button-accessible-name -- why this one is intended<Button variant="ghost" size="icon"> <Trash2 /></Button>onsystem-disable-next-line covers the next line, onsystem-disable-line its own, and /* onsystem-disable */ the rest of the file (at the top, the whole file). Without rule names they turn every rule off. A misspelled rule name is reported as a suppression warning, with the closest one, and suppresses nothing; syntax errors cannot be suppressed. For whole folders or kinds of files, such as legacy screens or generated code, use overrides in the config.