# Interactive Elements Missing ARIA Labels

**MUST** · **ID:** `interactions-rams-aria-labels` · **Category:** interactions
**Source:** [RAMS](https://www.rams.ai/)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/interactions-rams-aria-labels

> MUST: Icon-only buttons must have aria-label describing the action. Decorative icons need aria-hidden="true". Screen readers cannot interpret visual icons.

Interactive elements without visible text need aria-label or aria-labelledby

Rams ships this as a Critical checklist row, not prose. Our reading: screen readers announce the accessible name of interactive elements, so without one users hear only "button" with no indication of purpose. aria-label or aria-labelledby supplies that name.

## Bad — do not do this

`interactions-rams-aria-labels-bad`

```tsx
import { HugeiconsIcon } from '@hugeicons/react';
import { Cancel01Icon, PencilEdit02Icon, Delete02Icon } from '@hugeicons/core-free-icons';
import { ScreenReaderSim } from '@/components/ScreenReaderSim';

export function RamsAriaLabelsBad() {
  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="bg-card border border-border rounded-lg p-4">
        <h4 className="font-medium mb-3">Icon Buttons Missing Labels</h4>
        <ScreenReaderSim>
          <div className="space-y-3">
            <div className="flex gap-2 p-3 bg-muted rounded-lg">
              {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
              <button className="p-2 hover:bg-background rounded-md transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring">
                <HugeiconsIcon icon={PencilEdit02Icon} size={20} />
              </button>
              {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
              <button className="p-2 hover:bg-background rounded-md transition-colors text-destructive focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring">
                <HugeiconsIcon icon={Delete02Icon} size={20} />
              </button>
              {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
              <button className="p-2 hover:bg-background rounded-md transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring">
                <HugeiconsIcon icon={Cancel01Icon} size={20} />
              </button>
            </div>
            <div className="bg-muted rounded p-2 font-mono text-xs">
              <code className="text-error">{'<button><Icon /></button>'}</code>
            </div>
          </div>
        </ScreenReaderSim>
      </div>
      <p className="text-xs text-error">
        No label and no text, so each button is announced only as “button”.
      </p>
    </div>
  );
}
```

## Good — do this

`interactions-rams-aria-labels-good`

```tsx
import { HugeiconsIcon } from '@hugeicons/react';
import { Cancel01Icon, PencilEdit02Icon, Delete02Icon } from '@hugeicons/core-free-icons';
import { ScreenReaderSim } from '@/components/ScreenReaderSim';

export function RamsAriaLabelsGood() {
  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="bg-card border border-border rounded-lg p-4">
        <h4 className="font-medium mb-3">Icon Buttons with Labels</h4>
        <ScreenReaderSim>
          <div className="space-y-3">
            <div className="flex gap-2 p-3 bg-muted rounded-lg">
              <button
                aria-label="Edit item"
                className="p-2 hover:bg-background rounded-md transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
              >
                <HugeiconsIcon icon={PencilEdit02Icon} size={20} />
              </button>
              <button
                aria-label="Delete item"
                className="p-2 hover:bg-background rounded-md transition-colors text-destructive focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
              >
                <HugeiconsIcon icon={Delete02Icon} size={20} />
              </button>
              <button
                aria-label="Close"
                className="p-2 hover:bg-background rounded-md transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
              >
                <HugeiconsIcon icon={Cancel01Icon} size={20} />
              </button>
            </div>
            <div className="bg-muted rounded p-2 font-mono text-xs">
              <code>aria-label="Edit item"</code>
            </div>
          </div>
        </ScreenReaderSim>
      </div>
      <p className="text-xs text-success">
        Each icon button carries an <code>aria-label</code>, so it is announced by name.
      </p>
    </div>
  );
}
```

## References

- [Rams review checklist](https://www.rams.ai/rams.md)
- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html)
