Components / Actions
ExpandingButtonGroup
Icon buttons in a compact group: the one you point at or focus grows to reveal its label while its neighbours slide aside, and an action confirms in place.
Install
npx shadcn@latest add https://irisui.dev/r/expanding-button-group.jsonimport { ExpandingButtonGroup } from "@/components/iris/expanding-button-group/expanding-button-group";Preview
ExpandingButtonGroup
Icon buttons in a compact group: the one you point at or focus grows to reveal its label while its neighbours slide aside, and an action confirms in place.
When to use
- Dense per-item actions where icons alone are ambiguous but labels would crowd the row — message actions, AI response actions (Copy, Edit, Regenerate).
- Quick actions that should confirm without a toast: set
doneLabel("Archived") and the icon turns into a check. - When every label must always be visible, use
ButtonGroup. For a floating toolbar with tooltips, useFloatingButtonGroup.
Usage
import { ExpandingButtonGroup } from "@/components/iris/expanding-button-group/expanding-button-group";
<ExpandingButtonGroup
label="Letter actions"
items={[
{ id: "reply", label: "Reply", icon: <ReplyIcon size={16} /> },
{
id: "archive",
label: "Archive",
doneLabel: "Archived",
icon: <ArchiveIcon size={16} />,
onSelect: () => api.archiveLetter(id),
},
{
id: "delete",
label: "Delete",
doneLabel: "Deleted",
icon: <TrashIcon size={16} />,
tone: "danger",
onSelect: remove,
},
]}
/>;
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items |
ExpandingButtonGroupItem[] |
— | Required: { id, label, icon, onSelect?, doneLabel?, tone?, disabled? }. onSelect may return false or reject to skip the confirmation; a promise keeps the button busy. |
label |
string |
— | Accessible name of the toolbar (required). |
size |
"sm" | "md" |
"md" |
Button size. |
defaultExpanded |
string | null |
first enabled | Id of the action whose label shows at rest. One action is always expanded; it returns here when pointer and focus leave. |
onAction |
(id: string) => void |
— | Called with the item id before the item's own onSelect. |
confirmDuration |
number |
1400 |
How long the done state stays, in ms. |
className, style |
— | — | Passed to the root. |
Notes
- Renders
role="toolbar"with a roving tab stop; Left/Right, Home and End move focus, and focus expands the focused action. - Labels are always the accessible names, collapsed or not. A polite live region (
<output>) announces the done label; busy actions setaria-busy. tone: "danger"colours the expanded state with--red. Disabled actions stay focusable and still reveal their label.- Icons are sized by the group; a 16px icon fits.