IconButton

A square, icon-only button. Same visual language as Button — six variants, three sizes, the same radius scale — but optimised for label-less actions in toolbars and action rails. The required aria-label prop is enforced at the TypeScript level so missing accessible names get caught at build time.

When to use IconButton vs Button leftIcon

Both IconButton and <Button leftIcon> render an icon inside a clickable surface — but they read very differently and serve different jobs.

IconButton — square, label-less, for toolbars
Button leftIcon — rectangular, with a label

Usage

import { IconButton } from '@bwo-ui/react';

<IconButton aria-label="Search">
  <SearchIcon />
</IconButton>

Variants

IconButton mirrors every variant from Button: primary, green, yellow, ghost, outline, and solid. Pick the colour weighting that matches the action's emphasis — primary for default actions, ghost for ambient toolbars, green for confirm, yellow for callouts, outline for secondary, solid for the loud hero icon.

<IconButton variant="primary" aria-label="Next"><Arrow /></IconButton>
<IconButton variant="green"   aria-label="Confirm"><Check /></IconButton>
<IconButton variant="yellow"  aria-label="Highlight"><Star /></IconButton>
<IconButton variant="ghost"   aria-label="Menu"><Menu /></IconButton>
<IconButton variant="outline" aria-label="Edit"><Pencil /></IconButton>
<IconButton variant="solid"   aria-label="Action"><Bolt /></IconButton>

Note on solid: Button's solid variant gets its weight from extra padding and uppercase typography, neither of which applies to a square icon-only button. The IconButton equivalent keeps the primary colour and adds an elevation shadow, so it reads as the louder cousin of primary.

Sizes

Three sizes — sm (32 px), md (40 px, default), lg (48 px). The icon itself does not auto-scale; pass a larger inline SVG when you bump up the size if you need the visual to grow with the hit target.

<IconButton size="sm" aria-label="Next"><Arrow /></IconButton>
<IconButton            aria-label="Next"><Arrow /></IconButton>
<IconButton size="lg" aria-label="Next"><Arrow /></IconButton>

Corner radius

The radius prop accepts the shared Radius scale (none / sm / md / lg / pill). Omit it to inherit whatever --bwo-radius-current evaluates to in context.

<IconButton radius="none" aria-label="Add"><Plus /></IconButton>
<IconButton radius="sm"   aria-label="Add"><Plus /></IconButton>
<IconButton radius="md"   aria-label="Add"><Plus /></IconButton>
<IconButton radius="lg"   aria-label="Add"><Plus /></IconButton>
<IconButton radius="pill" aria-label="Add"><Plus /></IconButton>

Toolbar pattern

IconButton was built for tight horizontal action rails. Wrap them in a role="toolbar" container with a single aria-label describing the group, then let each button carry its own action-level label.

<div role="toolbar" aria-label="Item actions" style={{ display: 'inline-flex', gap: 6 }}>
  <IconButton variant="ghost" size="sm" aria-label="Like"><Heart /></IconButton>
  <IconButton variant="ghost" size="sm" aria-label="Share"><Share /></IconButton>
  <IconButton variant="ghost" size="sm" aria-label="Delete"><Trash /></IconButton>
</div>

Disabled

IconButton forwards every native button attribute, including disabled. For async actions, prefer disabling alongside a separate loading indicator — IconButton has no built-in loading prop because there is no label slot to swap with a spinner.

<IconButton aria-label="Delete" disabled>
  <Trash />
</IconButton>

Accessibility

Props

PropTypeDefaultDescription
variant'primary' | 'green' | 'yellow' | 'ghost' | 'outline' | 'solid''primary'Visual style. Mirrors the Button variants.
size'sm' | 'md' | 'lg''md'32 / 40 / 48 px square.
radius'none' | 'sm' | 'md' | 'lg' | 'pill'Corner radius preset. Omit to inherit `--bwo-radius-current` (defaults to 6 px globally).
aria-labelstringRequired. Describes the action for screen readers — icon-only buttons have no visible label.
…restButtonHTMLAttributes<HTMLButtonElement>All native button attributes are forwarded — `onClick`, `disabled`, `type`, `form`, `name`, etc.