ActionIcon
Square, icon-only sibling of Button. Same (variant × color) model plus its own radius scale.
ActionIcon is the icon-only counterpart to Button. It shares the same orthogonal (variant × color) model and adds its own radius scale so circular triggers (toolbars, like buttons, dismiss controls) drop straight in.
import { ActionIcon } from '@42/ui-react/action-icon';
import { Settings } from 'lucide-react';
<ActionIcon aria-label="Open settings">
<Settings />
</ActionIcon>The icon is auto-sized by the parent's size variant — drop in a bare lucide-react icon and you'll never need to set size={n} on it.
aria-label is required. The icon children are decoration — screen
readers won't announce them. Without a label, the trigger is effectively
invisible to assistive tech.
Playground
Component
Presets
Props
Code
<Component disabled={false} color="brand" variant="filled" size="xs" radius="sm" isLoading={false}/>Full prop browser
If you need to inspect every prop on ActionIconProps (including spread-through HTML attributes), use the kitchen-sink view.
Variants
Five visual treatments, identical in semantics to Button's. Each reads off the same color slots (--c-solid, --c-soft, --c-text) so palette swaps are uniform.
import { Star } from 'lucide-react';
<ActionIcon variant="filled" aria-label="Star"><Star /></ActionIcon>
<ActionIcon variant="light" aria-label="Star"><Star /></ActionIcon>
<ActionIcon variant="outline" aria-label="Star"><Star /></ActionIcon>
<ActionIcon variant="subtle" aria-label="Star"><Star /></ActionIcon>
<ActionIcon variant="default" aria-label="Star"><Star /></ActionIcon>subtle remains the toolbar workhorse: borderless, no resting fill, hover tint reveals the palette.
Colors
Every variant (except default) accepts any color from the shared palette.
<ActionIcon variant="filled" color="brand" aria-label="Favorite"><Heart /></ActionIcon>
<ActionIcon variant="light" color="blue" aria-label="Info"><Star /></ActionIcon>
<ActionIcon variant="outline" color="teal" aria-label="Toggle"><Star /></ActionIcon>
<ActionIcon variant="subtle" color="gray" aria-label="Bold"><Bold /></ActionIcon>
<ActionIcon variant="filled" color="red" aria-label="Delete"><Trash2 /></ActionIcon>For destructive triggers, use variant="filled" color="red" — there is no separate destructive variant.
Sizes
Five sizes from xs (compact toolbar) to xl (hero CTA). Each is square, with the icon scaling via 1em against the size's font-size.
<ActionIcon size="xs" aria-label="Star"><Star /></ActionIcon>
<ActionIcon size="sm" aria-label="Star"><Star /></ActionIcon>
<ActionIcon size="md" aria-label="Star"><Star /></ActionIcon>
<ActionIcon size="lg" aria-label="Star"><Star /></ActionIcon>
<ActionIcon size="xl" aria-label="Star"><Star /></ActionIcon>Radius
Independent radius scale, including full for circular triggers — perfect for FABs, like buttons, and avatar-adjacent controls.
<ActionIcon radius="sm" aria-label="Star"><Star /></ActionIcon>
<ActionIcon radius="md" aria-label="Star"><Star /></ActionIcon>
<ActionIcon radius="lg" aria-label="Star"><Star /></ActionIcon>
<ActionIcon radius="full" color="brand" aria-label="Add"><Plus /></ActionIcon>Loading
The icon is swapped for an inline spinner, the element is marked aria-busy="true", and pointer events are suppressed. The accessible name still comes from aria-label — screen readers will announce both the label and the busy state.
import { Star } from 'lucide-react';
const [pending, startTransition] = useTransition();
<ActionIcon
color="brand"
isLoading={pending}
aria-label="Star repository"
onClick={() => startTransition(toggleStar)}
>
<Star />
</ActionIcon>Toolbar pattern
A row of subtle ActionIcons with radius="md" is the workhorse for editor toolbars and table row actions.
import { Bold, Code, Italic, Link2, Underline } from 'lucide-react';
<div role="toolbar" aria-label="Format">
<ActionIcon variant="subtle" color="gray" size="sm" aria-label="Bold"><Bold /></ActionIcon>
<ActionIcon variant="subtle" color="gray" size="sm" aria-label="Italic"><Italic /></ActionIcon>
<ActionIcon variant="subtle" color="gray" size="sm" aria-label="Underline"><Underline /></ActionIcon>
</div>Polymorphic with asChild
Same Ark UI polymorphism as Button. Wrap a link to keep client-side navigation while inheriting the icon-button styling.
import Link from 'next/link';
import { User } from 'lucide-react';
<ActionIcon asChild variant="subtle" color="gray" aria-label="Open profile">
<Link href="/profile">
<User />
</Link>
</ActionIcon>API
Prop
Type
All other props are forwarded to the underlying button (or asChild element).
When to use which
- Reach for
Buttonwhen the trigger has a visible text label, with or without supporting icons. - Reach for
ActionIconwhen the trigger is icon-only and the meaning lives inaria-label+ tooltip. - For an icon plus a text label, use
ButtonwithleftSlot/rightSlot— notActionIcon.