ButtonGroup
Container component that wraps multiple ghost icon buttons with a unified 6% background. Use ButtonGroup as the container and ButtonGroupItem for each button.
Component
Import
tsx
import { ButtonGroup, ButtonGroupItem } from "@/components/ui/button-group";
import { DesignIcon } from "@/components/ui/design-icon";
Components
ButtonGroup (container), ButtonGroupItem (button)
Sizes
small (28px), default (32px), large (40px)
Icon Options
icon (<DesignIcon />) or iconUrl (SVG path)
Features
tooltip, active state, disabled, withSeparator

ButtonGroup Props

Container component props - wraps ButtonGroupItem children

Props
PropTypeDefaultDescription
size"small" | "default" | "large""default"Size of all buttons in the group (28px / 32px / 40px)
withSeparatorbooleanfalseAdd visual dividers between buttons
classNamestring-Additional CSS classes for the container
childrenReactNode-ButtonGroupItem components

ButtonGroupItem Props

Individual button props - must be a child of ButtonGroup

Props
PropTypeDefaultDescription
iconReactNode-DesignIcon component or any React SVG
iconUrlstring-Path to SVG file (uses CSS mask for theming)
tooltipstring-Tooltip text shown on hover
tooltipSide"top" | "bottom" | "left" | "right""bottom"Tooltip placement
disableTooltipbooleanfalseDisable tooltip even if tooltip prop is set
activebooleanfalseActive/pressed state (5% background + primary icon color)
disabledbooleanfalseDisabled state (44% opacity)
onClick(e) => void-Click handler
Common Patterns

Basic Media Toolbar

Image, GIF, emoji buttons with tooltips
<ButtonGroup>
  <ButtonGroupItem icon={<DesignIcon name="image" />} tooltip="Add image" />
  <ButtonGroupItem icon={<DesignIcon name="gif" />} tooltip="Add GIF" />
  <ButtonGroupItem icon={<DesignIcon name="emoji" />} tooltip="Add emoji" />
</ButtonGroup>

With Custom SVG Icons

Using iconUrl for custom SVG icons
<ButtonGroup>
  <ButtonGroupItem iconUrl="/imgs/icons/ic_image.svg" tooltip="Add image" />
  <ButtonGroupItem iconUrl="/imgs/icons/ic_gif.svg" tooltip="Add GIF" />
</ButtonGroup>

Toggle Toolbar with Active State

Buttons with active states for toggles
<ButtonGroup>
  <ButtonGroupItem icon={<DesignIcon name="link" />} tooltip="Add link" active={hasLink} onClick={toggleLink} />
  <ButtonGroupItem icon={<DesignIcon name="thread" />} tooltip="Thread" active={isThread} onClick={toggleThread} />
</ButtonGroup>

Small Size Group

Compact toolbar for tight spaces
<ButtonGroup size="small">
  <ButtonGroupItem icon={<DesignIcon name="move-up" />} tooltip="Move up" />
  <ButtonGroupItem icon={<DesignIcon name="move-down" />} tooltip="Move down" />
  <ButtonGroupItem icon={<DesignIcon name="delete" />} tooltip="Delete" />
</ButtonGroup>

Multiple Groups in Row

Separate logical button groups
<div className="flex items-center gap-2">
  <ButtonGroup>
    <ButtonGroupItem icon={<DesignIcon name="image" />} tooltip="Add image" />
    <ButtonGroupItem icon={<DesignIcon name="gif" />} tooltip="Add GIF" />
  </ButtonGroup>
  <ButtonGroup>
    <ButtonGroupItem icon={<DesignIcon name="ai" />} tooltip="AI assist" />
    <ButtonGroupItem icon={<DesignIcon name="duplicate" />} tooltip="Duplicate" />
  </ButtonGroup>
</div>
When to Use
1

Tweet composer media toolbar

Use default size with DesignIcon for consistent styling

<ButtonGroup>
  <ButtonGroupItem icon={<DesignIcon name="image" />} tooltip="Add image" />
  <ButtonGroupItem icon={<DesignIcon name="gif" />} tooltip="Add GIF" />
  <ButtonGroupItem icon={<DesignIcon name="emoji" />} tooltip="Add emoji" />
</ButtonGroup>
2

Action buttons with toggles

Use active prop to show current state

<ButtonGroup>
  <ButtonGroupItem icon={<DesignIcon name="link" />} tooltip="Link" active={hasLink} onClick={toggleLink} />
  <ButtonGroupItem icon={<DesignIcon name="thread" />} tooltip="Thread" active={isThread} onClick={toggleThread} />
</ButtonGroup>
3

Reorder/delete actions in list items

Use small size for compact UI

<ButtonGroup size="small">
  <ButtonGroupItem icon={<DesignIcon name="move-up" />} tooltip="Move up" disabled={isFirst} />
  <ButtonGroupItem icon={<DesignIcon name="move-down" />} tooltip="Move down" disabled={isLast} />
  <ButtonGroupItem icon={<DesignIcon name="delete" />} tooltip="Delete" />
</ButtonGroup>
4

Top placement tooltips (toolbar at bottom of screen)

Use tooltipSide='top' to prevent overflow

<ButtonGroup>
  <ButtonGroupItem icon={<DesignIcon name="image" />} tooltip="Add image" tooltipSide="top" />
  <ButtonGroupItem icon={<DesignIcon name="gif" />} tooltip="Add GIF" tooltipSide="top" />
</ButtonGroup>
Do

Always wrap ButtonGroupItem inside ButtonGroup

<ButtonGroup>
  <ButtonGroupItem icon={<DesignIcon name="image" />} tooltip="Add image" />
</ButtonGroup>

Add tooltips for accessibility

<ButtonGroupItem icon={<DesignIcon name="link" />} tooltip="Add link (⌘K)" />

Use active prop for toggle states

<ButtonGroupItem icon={<DesignIcon name="thread" />} active={isThread} onClick={toggleThread} />

Use DesignIcon for consistent design system styling

<ButtonGroupItem icon={<DesignIcon name="ai" />} tooltip="AI assist" />
Don't

Don't use ButtonGroupItem outside of ButtonGroup

// ❌ Bad - no container
<ButtonGroupItem icon={<DesignIcon name="image" />} />

// βœ… Good - wrapped in ButtonGroup
<ButtonGroup>
  <ButtonGroupItem icon={<DesignIcon name="image" />} />
</ButtonGroup>

Don't use text content - ButtonGroupItem is icon-only

// ❌ Bad - no text support
<ButtonGroupItem>Add Image</ButtonGroupItem>

// βœ… Good - use icon + tooltip
<ButtonGroupItem icon={<DesignIcon name="image" />} tooltip="Add Image" />

Don't mix icon and iconUrl - use one or the other

// ❌ Bad - conflicting props
<ButtonGroupItem icon={<DesignIcon name="image" />} iconUrl="/icon.svg" />

// βœ… Good - use one
<ButtonGroupItem icon={<DesignIcon name="image" />} />
// or
<ButtonGroupItem iconUrl="/imgs/icons/ic_image.svg" />

Visual Examples

Interactive examples showing all variants and states

Size Comparison

small (28px), default (32px), large (40px)

small
default
large
<ButtonGroup size="small">...</ButtonGroup>
<ButtonGroup>...</ButtonGroup>
<ButtonGroup size="large">...</ButtonGroup>

Active States

Toggle buttons showing active/inactive states

<ButtonGroup>
  <ButtonGroupItem icon={<DesignIcon name="link" />} active />
  <ButtonGroupItem icon={<DesignIcon name="thread" />} />
  <ButtonGroupItem icon={<DesignIcon name="bookmark" />} active />
</ButtonGroup>

Disabled Buttons

Individual buttons can be disabled

<ButtonGroup>
  <ButtonGroupItem icon={<DesignIcon name="move-up" />} disabled />
  <ButtonGroupItem icon={<DesignIcon name="move-down" />} />
  <ButtonGroupItem icon={<DesignIcon name="delete" />} />
</ButtonGroup>

Custom SVG Icons

Using iconUrl for mask-based icons

<ButtonGroup>
  <ButtonGroupItem iconUrl="/imgs/icons/ic_image.svg" tooltip="Image" />
  <ButtonGroupItem iconUrl="/imgs/icons/ic_gif.svg" tooltip="GIF" />
</ButtonGroup>

Multiple Groups

Separate logical button groups

<div className="flex items-center gap-2">
  <ButtonGroup>
    <ButtonGroupItem icon={<DesignIcon name="image" />} />
    <ButtonGroupItem icon={<DesignIcon name="gif" />} />
  </ButtonGroup>
  <ButtonGroup>
    <ButtonGroupItem icon={<DesignIcon name="ai" />} />
    <ButtonGroupItem icon={<DesignIcon name="duplicate" />} />
  </ButtonGroup>
</div>

Real World: Tweet Composer

Media toolbar with actions

<div className="flex items-center gap-2">
  <ButtonGroup>
    <ButtonGroupItem icon={<DesignIcon name="image" />} tooltip="Add image" />
    <ButtonGroupItem icon={<DesignIcon name="gif" />} tooltip="Add GIF" />
    <ButtonGroupItem icon={<DesignIcon name="emoji" />} tooltip="Add emoji" />
  </ButtonGroup>
  <ButtonGroup>
    <ButtonGroupItem icon={<DesignIcon name="ai" />} tooltip="AI assist" />
  </ButtonGroup>
</div>