Button Group

Grouped controls for adjacent actions, segmented selection, labels, separators, and toolbar layouts.

Installation

npx shadcn@latest add @iconiq/button-group

File Structure

Usage

"use client";

import { MoreHorizontalIcon } from "lucide-react";

import {
  Button,
  ButtonGroup,
  IconButton,
} from "@/components/ui/button-group";

export function ButtonGroupDemo() {
  return (
    <ButtonGroup aria-label="Project actions" size="sm">
      <Button>Edit</Button>
      <Button>Preview</Button>
      <Button>Publish</Button>
      <IconButton aria-label="More project actions">
        <MoreHorizontalIcon />
      </IconButton>
    </ButtonGroup>
  );
}

Props

Props
Description

Button

children

Button content rendered inside an inline span so icon-and-label pairs keep consistent spacing across sizes.

Type ReactNode

className

Merged onto the root button. Use it for local width, spacing, or surface overrides.

Type string

size

Compacts or expands the control. Inherits the ButtonGroup size when the button is rendered inside a group.

Type "sm" | "md" | "lg"·Default "md"

variant

Visual treatment for the action. Destructive is useful for delete or irreversible actions inside a toolbar.

Type "default" | "destructive" | "ghost" | "outline"·Default "default"

disableRipple

Turns off the click ripple while preserving the rest of the hover and focus styling.

Type boolean·Default false

showBorder

Adds a standalone border when the button is used outside ButtonGroup. Inside ButtonGroup, the wrapper supplies the outer border and dividers instead.

Type boolean·Default true

IconButton

children

Icon content rendered inside the inline content span. SVG children inherit the built-in size utilities for the active size variant.

Type ReactNode

className

Merged onto the icon button root for size or surface overrides.

Type string

size

Controls the square footprint of the icon button. Inherits the ButtonGroup size when rendered inside a group.

Type "sm" | "md" | "lg"·Default "md"

variant

Matches the Button variant surface for icon-only actions.

Type "default" | "destructive" | "ghost" | "outline"·Default "default"

disableRipple

Disables the click ripple for quieter toolbar actions.

Type boolean·Default false

showBorder

Removes the outer border when set to false so the icon action can sit more quietly beside a borderless group.

Type boolean·Default true

ButtonGroup

children

Buttons, icon buttons, ButtonGroupText, ButtonGroupSeparator, ButtonGroupItems, or any other data-slot controls you want to keep together.

Type ReactNode

orientation

Chooses the grouped rounding and shared-border direction used by buttonGroupVariants.

Type "horizontal" | "vertical"·Default "horizontal"

size

Shared density for Button, IconButton, and ButtonGroupText children unless a child overrides size locally.

Type "sm" | "md" | "lg"·Default "md"

className

Merged onto the outer group. Use it for wrapping, alignment, or local spacing overrides.

Type string

ButtonGroupText

children

Short label or inline content rendered inside the grouped text segment.

Type ReactNode

render

Optional Base UI render override when you need a different element while keeping the same merged props.

Type useRender render prop

className

Merged with the default muted bordered text segment classes.

Type string

ButtonGroupSeparator

orientation

Controls the separator axis. Vertical separators are the default for horizontal button groups.

Type "horizontal" | "vertical"·Default "vertical"

className

Merged with the self-stretching separator classes for custom color or spacing.

Type string

ButtonGroupItems

children

Pass plain button-like elements as children. Their props and children are hoisted into the internal motion buttons rendered by the group.

Type ReactNode

className

Merged onto the outer segmented wrapper for width or surface overrides.

Type string

size

Sets the shared height, padding, and typography of the grouped buttons.

Type "sm" | "md" | "lg"·Default "md"

showDividers

Removes the internal separator lines and the outer wrapper border when set to false, then switches the group to a smoother shared hover surface.

Type boolean·Default true

disableRipple

Turns off the ripple for every internal button rendered by the group.

Type boolean·Default false

SegmentedControl

options

Ordered list of segments. Each entry can be a plain string or an object with a stable value, optional label, icon, and disabled flag.

Type Array<string | { value: string; label?: ReactNode; disabled?: boolean; icon?: ReactNode }>

value

Controlled selected value. When provided, the internal state syncs to this prop through an effect.

Type string

onChange

Called with the selected value whenever a segment is pressed or moved to with the keyboard.

Type (value: string) => void

ariaLabel

Accessible name for the radiogroup. Provide this or ariaLabelledBy so screen readers can identify the control.

Type string

ariaLabelledBy

ID of an external label element that names the radiogroup. Use when a visible label already exists in the page.

Type string

name

When provided, renders a hidden input so the selected value can participate in native form submission.

Type string

disabled

Disables the entire control and every segment inside it.

Type boolean·Default false

orientation

Layout direction for the segmented shell and the primary arrow-key axis.

Type "horizontal" | "vertical"·Default "horizontal"

className

Merged onto the segmented wrapper for width, alignment, or spacing overrides.

Type string

layoutId

Optional Motion layout id for the selected indicator. When omitted, a unique id is generated per instance so multiple controls on one page do not share indicator motion.

Type string

size

Controls the overall density of the segmented control shell and each segment inside it.

Type "sm" | "md" | "lg"·Default "md"

Motion and interaction

Each export keeps the same tactile feel, but the default presentation is now much more compact and toolbar-like.

Button, IconButton, and ButtonGroupItems all default to muted text that darkens on hover, which better matches compact shadcn-style controls.

ButtonGroup applies embedded theme tokens once at the group root so nested buttons do not repeat the full token block.

The ButtonGroup wrapper uses the exported buttonGroupVariants CVA recipe, while existing motion-powered controls keep their ripple and shared-hover behavior.

Ripple feedback can now be turned off per surface, which is useful when you want a quieter desktop toolbar feel.

SegmentedControl keeps motion focused on selection changes rather than entrance effects, so the control feels faster and less oversized.

Registry bundle

Install the exact registry entry shown on the right when you want the component file and its declared runtime dependencies together.

Dependencies: @base-ui/react, motion, class-variance-authority.

Contact

Additionally, if you find any bug or issue, feel free to raise an issue.

Review the latest project changes before sharing them with your team.