IconButton
Status: stableAccessibility reviewedtenet-ui@0.4.0
import { IconButton } from 'tenet-ui';Also accepts every prop of ButtonHTMLAttributes<HTMLButtonElement>.
Source: src/components/IconButton/IconButton.tsx
Usage guidelines
Section titled “Usage guidelines”A square, icon-only button for compact actions where a text label won’t fit.
When to use
Section titled “When to use”- Use IconButton for dense surfaces: toolbars, table-row actions, the close affordance in a dialog/banner corner, segmented toolbars.
- Use Button (with a
leadingIcon) whenever you have room for a label — a visible label is always clearer than an icon alone. Reach for IconButton only when space is genuinely the constraint. - For a menu of actions behind one trigger, use Menu; IconButton is a single action, not a disclosure.
- It must have an accessible name. The icon is the only visible content and is
rendered
aria-hidden, so the name has to come fromaria-label(oraria-labelledby). With neither, screen-reader users hear nothing. In development the component logs aconsole.warnwhen the name is missing. - The name should describe the action, not the glyph:
aria-label="Delete row", notaria-label="Trash icon". - Variants mirror
Button:primaryfor the single most important action,defaultfor secondary,invisiblefor tertiary/toolbar,dangerfor destructive. - Sizes map to the control-height tokens (
small28 /medium32 /large40) and the control is square, so it lines up with same-size inputs and buttons. - The whole control is a real
<button>, so keyboard activation (Enter/Space) and the:focus-visiblering come for free. Passdisabledas usual.
Do / Don’t
Section titled “Do / Don’t”Do — give it an action name and pass the icon via the icon prop:
<IconButton icon={<TrashIcon />} variant="danger" aria-label="Delete row" onClick={remove} />Don’t — ship a nameless icon button (axe failure; the dev warning fires):
// ❌ no accessible name — screen readers announce nothing<IconButton icon={<TrashIcon />} variant="danger" onClick={remove} />Don’t — bake the label into the icon and leave the button unnamed:
// ❌ the <span> text is aria-hidden with the icon; the button is still nameless<IconButton icon={<><TrashIcon /> Delete</>} />See also: Button with leadingIcon when a label fits, Tooltip to reveal the name on hover; system guidelines iconography and accessibility.
Examples
Section titled “Examples”5 stories for IconButton — open in Storybook
- Default
components-iconbutton--default - Primary
components-iconbutton--primary - Danger
components-iconbutton--danger - Invisible
components-iconbutton--invisible - Sizes
components-iconbutton--sizes
The full matrix (all args, controls, accessibility panel) is in Storybook.
| Prop | Type | Default | Description |
|---|---|---|---|
icon * | ReactNode | — | The icon to render. This is the only visible content, so the button must also have an accessible name. |
variant | 'default' | 'primary' | 'danger' | 'invisible'IconButtonVariant | default | Visual style of the button. Use primary for the single most important action per surface. |
size | 'small' | 'medium' | 'large'IconButtonSize | medium | Square control size (height = width), mapped to the control-height tokens. |
* required