# Icon Buttons Need Labels

**MUST** · **ID:** `interactions-ibelick-icon-buttons` · **Category:** interactions
**Source:** [@Ibelick](https://www.ui-skills.com/)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/interactions-ibelick-icon-buttons

> MUST: Add aria-label to icon-only buttons describing the action. "Close", "Delete", "Edit" - not "X icon" or "Trash icon". Screen readers need action context.

Always add aria-label to icon-only buttons for screen reader users

Icon-only buttons have no visible text, so screen readers have nothing to announce — users hear only "button" with no context. An aria-label supplies that name. Pair it with aria-hidden="true" on the icon itself so the glyph is not announced twice.

## Bad — do not do this

`interactions-ibelick-icon-buttons-bad`

```tsx
import { ScreenReaderSim } from '@/components/ScreenReaderSim';

const buttonClass =
  'p-2 rounded-lg bg-muted hover:bg-muted/80 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring';

export function IbelickIconButtonsBad() {
  return (
    <div className="space-y-4">
      <ScreenReaderSim>
        <div className="flex gap-2">
          {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
          <button className={buttonClass}>
            <svg className="size-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
            </svg>
          </button>
          {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
          <button className={buttonClass}>
            <svg className="size-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
            </svg>
          </button>
          {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
          <button className={buttonClass}>
            <svg className="size-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
            </svg>
          </button>
        </div>
      </ScreenReaderSim>
      <p className="text-xs text-destructive">
        No <code>aria-label</code> and no text — each button announces only as “button”, with no purpose.
      </p>
    </div>
  );
}
```

## Good — do this

`interactions-ibelick-icon-buttons-good`

```tsx
import { ScreenReaderSim } from '@/components/ScreenReaderSim';

const buttonClass =
  'p-2 rounded-lg bg-muted hover:bg-muted/80 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring';

export function IbelickIconButtonsGood() {
  return (
    <div className="space-y-4">
      <ScreenReaderSim>
        <div className="flex gap-2">
          <button aria-label="Open menu" className={buttonClass}>
            <svg className="size-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
            </svg>
          </button>
          <button aria-label="Search" className={buttonClass}>
            <svg className="size-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
            </svg>
          </button>
          <button aria-label="Close dialog" className={buttonClass}>
            <svg className="size-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
            </svg>
          </button>
        </div>
      </ScreenReaderSim>
      <p className="text-xs text-success">
        Focus or hover each button — <code>aria-label</code> makes it announce its purpose.
      </p>
    </div>
  );
}
```

## References

- [ibelick/ui-skills — baseline-ui](https://github.com/ibelick/ui-skills)
- [Icon Button Accessibility](https://www.sarasoueidan.com/blog/accessible-icon-buttons/)
