# Icon button

Package: @commenda/pathfinder@0.1.0
Page: /docs/components/icon-button
Figma: https://www.figma.com/design/dn7BkGYEfIyP0o2zfesfVh/The-System?node-id=61-3

```tsx
import { IconButton } from '@commenda/pathfinder/icon-button';
import { PlusIcon } from '@commenda/pathfinder/icons/PlusIcon';

<IconButton label="Add entity">
  <PlusIcon />
</IconButton>;
```


## Usage [#usage]

```tsx
import { IconButton } from '@commenda/pathfinder/icon-button';
import { Trash01Icon } from '@commenda/pathfinder/icons/Trash01Icon';

<IconButton
  label="Delete entity"
  destructive
  disabled={!canDelete}
  disabledReason="Only administrators can delete entities"
  onClick={onDelete}
>
  <Trash01Icon />
</IconButton>;
```

## Installation [#installation]

```sh
pnpm --filter your-app add "@commenda/pathfinder@workspace:*"
```

The package currently lives in the Commenda workspace. External installation requires a published version or packed tarball. Import the precompiled stylesheet once; no application Tailwind setup is required.

## Examples [#examples]

### Variants [#variants]

Primary, Secondary, Tertiary and Plain. Hover or focus each example to inspect its interactive states and tooltip.


```tsx
<>
  <IconButton variant="primary" label="Add entity">
    <PlusIcon />
  </IconButton>
  <IconButton variant="secondary" label="Add entity">
    <PlusIcon />
  </IconButton>
  <IconButton variant="tertiary" label="Add entity">
    <PlusIcon />
  </IconButton>
  <IconButton variant="plain" label="Add entity">
    <PlusIcon />
  </IconButton>
</>;
```


### Sizes [#sizes]


```tsx
<>
  {(['xs', 'sm', 'md', 'lg'] as const).map((size) => (
    <IconButton key={size} size={size} label="Add entity">
      <PlusIcon />
    </IconButton>
  ))}
</>;
```


### Destructive variants [#destructive-variants]

Primary, Secondary and Tertiary support destructive actions. Plain intentionally does not.


```tsx
<>
  <IconButton variant="primary" label="Delete entity" destructive>
    <Trash01Icon />
  </IconButton>
  <IconButton variant="secondary" label="Delete entity" destructive>
    <Trash01Icon />
  </IconButton>
  <IconButton variant="tertiary" label="Delete entity" destructive>
    <Trash01Icon />
  </IconButton>
</>;
```


### Disabled with a reason [#disabled-with-a-reason]

All four variants support disabled actions. Focus or hover to read the reason; activation remains blocked.


```tsx
<>
  {(['primary', 'secondary', 'tertiary', 'plain'] as const).map((variant) => (
    <IconButton
      key={variant}
      variant={variant}
      label="Add entity"
      disabled
      disabledReason="Administrator access required"
    >
      <PlusIcon />
    </IconButton>
  ))}
</>;
```


## API reference [#api-reference]

| Prop | Type | Requirement | Behavior |
| --- | --- | --- | --- |
| `label` | `string` | required | Visible field label. Supply an accessible name when it is omitted. |
| `children` | `ReactElement<any, string \| React.JSXElementConstructor<any>>` | required |  |
| `className` | `string` | optional | Additional classes for the component root. |
| `size` | `"sm" \| "md" \| "lg" \| "xs"` | optional |  |
| `disabledReason` | `string` | optional |  |
| `tooltip` | `boolean` | optional | Disable the automatic hint when an explicit Tooltip wraps this control. |
| `variant` | `"primary" \| "secondary" \| "tertiary" \| "plain"` | conditional |  |
| `destructive` | `boolean \| false` | optional |  |

`ICON-BUTTON-A11Y-01`: Name the action and target, not the glyph. “More options for Meridian UK Ltd” is useful; “Dots” is not. A disabled reason supplements this name. Tooltips work on focus and hover. With a reason, the disabled control remains focusable but cannot activate. `aria-pressed` is available for toggle actions.

Use tertiary for repeated row actions, secondary when an edge is needed and primary for the single main icon action such as Send. Plain has no hover background. xs is for input clear/chip close controls; never nest a button inside another button. Use a labeled Button when the icon is unfamiliar. Icons use 16px optical artwork through md and 20px at lg. Visual square size alone does not guarantee an adequate touch target; allocate sufficient spacing/hit area in touch layouts.

Import `@commenda/pathfinder/styles.css` once at the app root. Event handlers require a client component in Next.js App Router.

Set `tooltip={false}` when an explicit [Tooltip](/docs/components/tooltip) wraps the control, so it receives one hint. The accessible `label` remains required.

## Design rules [#design-rules]

Figma guidance and reviewed implementation decisions for this component. Rule IDs remain stable for source comments and AI references.

### Action rules [#action-rules]

- `CONTROL-SIZE-01` — Figma: Button and SplitButton sm/md/lg have 28/32/36px visual heights; md default. IconButton adds xs 24. Button icons are 16 through md and 20 at lg; pass size to generated icons to select optical artwork. Link styles have text-sized geometry. Long content can increase minimum height for accessibility.

- `CONTROL-FOCUS-01` — Figma: show focus from keyboard, not pointer click. Button family uses a blue ring separated by a white gap. Open triggers retain hover styling. Disabled reason is a Pathfinder extension: retain action name, expose description, and allow focus without activation where the native wrapper supports it.

- `ICON-BUTTON-A11Y-01` — Figma: labels are required and repeated in tooltips. Name action/target, never the glyph. Use familiar icons; otherwise use a text Button. Primary is reserved for the single main icon action. xs is reserved for controls inside a field/chip visually, never nested interactive markup. Touch layouts need adequate target space; 32/36px visual bounds do not themselves provide 44px targets.
