# Icon button

An icon button runs an action with just an icon, like close, copy or more.

## When to use

- For actions people know by their icon: close, back, copy, share, refresh, more.
- When space is tight and the same action repeats, like copy and explorer links on every address row.

## When not to use

- If people would have to guess what the icon does, use a [Button](/components/button/) with a label.
- For the main action in a view, use a primary Button. Icon buttons are never primary.
- To pick one of a few options, even with icons, use a [Segmented control](/components/segmented-control/).
- To turn a setting on or off, use a [Switch](/components/switch/).

## Anatomy

## Variants

- **Secondary** (the default) has a fill and a border. Use it when the button sits on its own, like a refresh button in a header.
- **Ghost** shows a fill only on hover. Use it in rows, dialog headers and groups, where many buttons sit close together.

The fills are the same as Button's secondary and ghost. The icon rests at `icon/secondary`, a step quieter than a label, and turns `icon/primary` on hover, press and while its menu is open.

## Sizes

- **Small** (32px, 20px icon) fits cards and dialog headers. In dense rows, like copy and explorer actions beside an address, give the icon `className="size-4"` for a 16px icon.
- **Medium** (40px, 24px icon) is the default, for page headers and toolbars.

Icon buttons that sit side by side should be the same size and variant. Every icon draws the same 1.67px line at any size, matching Button.

## Group

`IconButtonGroup` keeps related actions together in one pill. Buttons inside it are small and ghost unless you set otherwise. Give the group a `label`. Each button is its own <kbd>Tab</kbd> stop.

## States

Try the playground to see hover, pressed and focus. A pressed icon button shrinks slightly, to 95%, unless the user has turned on reduced motion. That's a little more than Button's 97%, which is too small to feel at 32px.

### Done

When an action finishes in place, like copy, swap the icon to a check for a moment. Wrap the icons in `IconSwap` so the old one shrinks away and the new one grows in, and use `DrawnCheck` so the check strokes itself in. Neither animates on first render, and with reduced motion the swap is a plain fade.

```tsx
<IconButton label="Copy token address" onClick={() => copy(address)}>
  <IconSwap swapKey={copied ? "check" : "copy"}>
    {copied ? <DrawnCheck className="text-positive" /> : <IconCopy />}
  </IconSwap>
</IconButton>
```

### Disabled

Disable an icon button only when you have to, and say why nearby. Hiding an action that never applies is often clearer.

## Content

- The `label` names the action, not the icon: *Close dialog*, not *X*.
- Use sentence case and no full stop. Name the thing when it helps: *Copy token address* is clearer than *Copy*.
- Use Tabler icons at stroke 2, the same icon for the same action everywhere.

## Behaviour

| Key | Action |
| --- | --- |
| <kbd>Tab</kbd> | Moves focus to the icon button. |
| <kbd>Enter</kbd> or <kbd>Space</kbd> | Runs the action. |

With `asChild` and a link, <kbd>Enter</kbd> follows the link and <kbd>Space</kbd> doesn't, as for any link.

## Accessibility

- `label` is required and becomes the `aria-label`. It's the only name screen readers get.
- The `label` also shows in a [Tooltip](/components/tooltip/) on hover and keyboard focus. Touch screens never show it, so still pick icons people already know.
- For a button that toggles, like show and hide, set `aria-pressed` or change the `label` with the state, never both.
- Keyboard focus shows the same 2px ring with a 2px gap as Button. Don't remove it.

## Props

| Prop | Type | Default | Notes |
| --- | --- | --- | --- |
| `label` | `string` | (required) | The accessible name. |
| `variant` | `"secondary"` \| `"ghost"` | `"secondary"` | `"ghost"` inside an `IconButtonGroup`. |
| `size` | `"sm"` \| `"md"` | `"md"` | `"sm"` inside an `IconButtonGroup`. |
| `asChild` | `boolean` | `false` | Gives the child, usually a link, the icon button's styles. |
| `tooltip` | `boolean` | `true` | Shows the `label` in a Tooltip. Turn off when the same words sit beside the button. |
| `tooltipSide` | `"top"` \| `"right"` \| `"bottom"` \| `"left"` | `"top"` | Where the tooltip opens. |

Every other `<button>` prop passes through, including `disabled`, `onClick` and `aria-pressed`. `IconButtonGroup` takes a required `label` and passes other props to its `<div>`.

## Related

- A [Button](/components/button/) runs an action with a label, with or without an icon.
- A [Segmented control](/components/segmented-control/) picks one of a few options.
