Button Group
Set the iconOnly prop on ButtonGroup to style each button for a single icon. This is useful for compact toolbars where a row of icon buttons act as related actions. Each button is configured through the buttonsProps array, and can carry a tooltip or a dropdown.
For the full API and general (text) button groups, see Button Group.
Installation
import { ButtonGroup, IconV2, DropdownMenu } from '@harnessio/ui/components'
return ( <ButtonGroup iconOnly size="sm" buttonsProps={[ { children: <IconV2 name="info-circle" />, onClick: () => { console.log('Button icon') } }, { children: <IconV2 name="key-back" />, tooltipProps: { title: 'Title', content: <p>This is a tooltip</p> }, onClick: () => { console.log('Button with tooltip') } }, { children: <IconV2 name="more-vert" />, dropdownProps: { content: ( <> <DropdownMenu.Item title="Item title" /> <DropdownMenu.Item title="With description" description="Item description" /> <DropdownMenu.Separator /> <DropdownMenu.Item title="With label" label="Label" /> <DropdownMenu.Item title="With checkmark" checkmark /> <DropdownMenu.Item title="With shortcut" shortcut="⇧⌘P" /> </> ) } } ]} />)Icon only
The ButtonGroup component accepts an iconOnly prop. When this prop is set, each button is styled to fit the dimensions of an icon, making it suitable for icon-only buttons.
With tooltip
Within buttonsProps, you can provide tooltipProps to define tooltip data for a specific button.
Anatomy
An icon button group is Button Group rendered with iconOnly, so it’s a row (or column) of joined icon-only Buttons. It’s composed of:
- Container — a wrapper that joins the buttons visually into one connected unit, laid out
horizontalby default orvertical. The first and last buttons get the group’s outer rounded corners. - Buttons — each entry in
buttonsPropsrenders one icon-only button, styledoutlineby default and sharing the group’ssize. Every button holds a singleIconV2. - Tooltip (per button) — supply
tooltipPropson a button to surface a label on hover and focus; its side follows the orientation (top when horizontal, right when vertical). - Dropdown (per button, optional) — supply
dropdownPropsinstead oftooltipPropsto make a button open aDropdownMenuof further actions.
Each button takes either tooltipProps or dropdownProps, not both.
Best practices
Do
- Use an icon button group for a small set of closely-related actions that belong together — a formatting cluster, a view switcher, a row of table actions.
- Give every button a
tooltipPropslabel so each icon’s meaning is discoverable on hover and focus. - Use the last button’s
dropdownPropsfor an overflow or “more” menu when there are secondary actions that don’t warrant their own icon. - Keep the set short; a handful of icons reads as a group, a dozen reads as a toolbar.
Don’t
- Don’t mix unrelated actions into one group — the joined styling signals the buttons belong together.
- Don’t rely on
dropdownPropsbuttons alone for their label; a dropdown button takes no tooltip, so give it anaria-label(see Accessibility). - Don’t reach for a group when a single Icon Button will do; the connected styling only makes sense for two or more.
Content
- Icon button groups have no text of their own — each button’s label lives in its
tooltipProps(andaria-label). - Name each action with a verb and sentence case — “Bold”, “Align left”, “More actions”.
- Keep the labels parallel across the group so the set reads consistently.
Accessibility
An icon button group is a set of icon-only buttons, so the accessibility work is the same as a single Icon Button, repeated per button — plus one gap in how the group itself is announced.
Keyboard
- Each button is a native
<button>: an individual tab stop, activated with Enter and Space. - There’s no arrow-key roving between the buttons — every button is its own tab stop, and a button carrying
dropdownPropsopens its menu with Enter/Space like any dropdown trigger. - Tooltips open on focus as well as hover, so keyboard users see each label as they tab through.
Labeling
- For buttons with
tooltipProps, the tooltip text is associated as a description (aria-describedby) through the underlying Radix tooltip — it is not turned into an accessible name. - For a reliable name, pass
aria-labelon each button inbuttonsProps(it’s forwarded to the<button>); match it to the tooltip text. - The icons carry no text, so they can’t be the only source of meaning.
Focus & states
- Each button shows the standard keyboard focus ring (
:focus-visible) via the--cn-focustoken. - The joined styling is purely visual; focus moves button to button in DOM order.
Known limitations
- A tooltip is a description, not a name. As with the base Icon Button,
tooltipPropsgives a description rather than an accessible name, so add an explicitaria-labelto each button for anything important. - Dropdown buttons have no label unless you add one. A button with
dropdownPropscan’t taketooltipProps, so it has neither a tooltip nor an automatic name — always give these buttons anaria-label(e.g. “More actions”). - The group isn’t announced as a set. The container is a plain
<div>with norole="group"or group label, so assistive tech reads the buttons individually rather than as one named group. If the grouping carries meaning, wrap it with your ownrole="group"andaria-label.
Properties
Type ButtonGroupButtonProps
type ButtonGroupTooltipProps = Pick< TooltipProps, "title" | "content" | "side" | "align">;
type BaseButtonProps = Omit< ButtonProps, "variant" | "size" | "theme" | "asChild" | "iconOnly" | "rounded" | "type">;
type DropdownPropsType = { content: ReactNode; contentProps?: typeof DropdownMenu.Content;};
type ButtonWithTooltip = BaseButtonProps & { tooltipProps: ButtonGroupTooltipProps; dropdownProps?: undefined;};
type ButtonWithDropdown = BaseButtonProps & { dropdownProps: DropdownPropsType; tooltipProps?: undefined;};
type ButtonGroupButtonProps = ButtonWithTooltip | ButtonWithDropdown;Prop | Required | Default | Type |
|---|---|---|---|
| iconOnly | false | boolean | |
| buttonsProps | true | ButtonGroupButtonProps[] | |
| orientation | false | horizontal | 'horizontal' | 'vertical' |
| size | false | md | 'md' | 'sm' | 'xs' |
| className | false | string |