# IconButton

> Slug: `icon-button` · Category: Actions

## When to use
- Provide a compact, icon-only control: close, more, favorite, share, edit.
- Place inside dense surfaces (toolbars, list rows, card corners) where a labeled `Button` is too large.
- Render notification chrome with an unread badge (`hasBadge` + `badgeNumber`).

## When NOT to use
- The action benefits from a visible text label — use `Button` for clarity.
- Inline text affordance — use `Link` or `ButtonStyledAsLink`.
- Navigation — wrap appropriately or use anchor-based affordances.

## Variants & decision tree
- Bare icon on transparent background -> `background="none"` (default).
- Filled circle treatment -> `background="primary"` or `background="secondary"`.
- Sizes: `large`, `small`, `xs` via `size`.
- With unread/notification count -> `hasBadge` + `badgeNumber` (numbers >99 render as `99+`; 0 renders an empty badge dot).

## States
- `disabled` — uses native `disabled` AND `aria-disabled`.
- Force-state props for design review: `focused`, `hover`, `pressed`.
- Inverse via theme or `inverse` prop.

## Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| **`a11yLabel`** | `string` | — | **Required**. Accessible name. Empty string returns `null`. |
| **`icon`** | `ReactNode` | — | SVG icon element. |
| `size` | `'large' \| 'small' \| 'xs'` | `'large'` | Render size. |
| `background` | `'none' \| 'secondary' \| 'primary'` | `'none'` | Background fill. |
| `hasBadge` | `boolean` | `false` | Render notification badge. |
| `badgeNumber` | `number` | `0` | Badge count; >99 displays as `99+`. |
| `inverse` | `boolean` | inherits | Dark-background styling. |
| `disabled` | `boolean` | `false` | Disables the button. |
| `ariaHasPopup` | `boolean` | — | Set when triggering a menu. |
| `ariaControls` | `string` | — | Controlled element id. |
| `ariaExpanded` | `boolean` | — | Expanded state when controlling a menu. |
| `describedBy` | `string` | — | `aria-describedby`. |
| `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | Native type. |

## Usage examples
```tsx
import { IconButton } from 'arrow-react-bootstrap';
const CloseIcon = <svg viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>;

// Toolbar close
<IconButton a11yLabel="Close" icon={CloseIcon} onClick={close} />

// Notification bell with unread count
<IconButton a11yLabel="Notifications" icon={BellIcon} hasBadge badgeNumber={12} background="secondary" />

// Trigger a menu
<IconButton
  a11yLabel="More options"
  icon={MoreIcon}
  ariaHasPopup
  ariaControls="row-menu"
  ariaExpanded={open}
/>
```

## Composition
- Built into `Tidbit` for the dismiss affordance.
- Use as the trigger for `Menu` / `MenuDropdown` on toolbars or list rows.
- Pair with `Avatar` and `SectionHeader` for header chrome.

## Accessibility
- `a11yLabel` is required — sets `aria-label`. Without it the component returns `null`.
- When `hasBadge` is set, the badge count is appended to the accessible name (e.g., "Notifications, 12").
- Pass `ariaHasPopup`, `ariaControls`, `ariaExpanded` when used as a menu trigger.

## Do / Don't
- Do: always pass a meaningful `a11yLabel`.
- Do: use real SVG `ReactNode` for `icon`, never strings or icon names.
- Don't: rely on tooltip-only labeling; the `aria-label` is the source of truth.
- Don't: use for navigation between routes.
