Grouped controls for adjacent actions, segmented selection, labels, separators, and toolbar layouts.
npx shadcn@latest add @iconiq/button-group"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>
);
}childrenButton content rendered inside an inline span so icon-and-label pairs keep consistent spacing across sizes.
Type ReactNode
classNameMerged onto the root button. Use it for local width, spacing, or surface overrides.
Type string
sizeCompacts or expands the control. Inherits the ButtonGroup size when the button is rendered inside a group.
Type "sm" | "md" | "lg"·Default "md"
variantVisual treatment for the action. Destructive is useful for delete or irreversible actions inside a toolbar.
Type "default" | "destructive" | "ghost" | "outline"·Default "default"
disableRippleTurns off the click ripple while preserving the rest of the hover and focus styling.
Type boolean·Default false
showBorderAdds 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
childrenIcon content rendered inside the inline content span. SVG children inherit the built-in size utilities for the active size variant.
Type ReactNode
classNameMerged onto the icon button root for size or surface overrides.
Type string
sizeControls the square footprint of the icon button. Inherits the ButtonGroup size when rendered inside a group.
Type "sm" | "md" | "lg"·Default "md"
variantMatches the Button variant surface for icon-only actions.
Type "default" | "destructive" | "ghost" | "outline"·Default "default"
disableRippleDisables the click ripple for quieter toolbar actions.
Type boolean·Default false
showBorderRemoves the outer border when set to false so the icon action can sit more quietly beside a borderless group.
Type boolean·Default true
childrenButtons, icon buttons, ButtonGroupText, ButtonGroupSeparator, ButtonGroupItems, or any other data-slot controls you want to keep together.
Type ReactNode
orientationChooses the grouped rounding and shared-border direction used by buttonGroupVariants.
Type "horizontal" | "vertical"·Default "horizontal"
sizeShared density for Button, IconButton, and ButtonGroupText children unless a child overrides size locally.
Type "sm" | "md" | "lg"·Default "md"
classNameMerged onto the outer group. Use it for wrapping, alignment, or local spacing overrides.
Type string
childrenShort label or inline content rendered inside the grouped text segment.
Type ReactNode
renderOptional Base UI render override when you need a different element while keeping the same merged props.
Type useRender render prop
classNameMerged with the default muted bordered text segment classes.
Type string
orientationControls the separator axis. Vertical separators are the default for horizontal button groups.
Type "horizontal" | "vertical"·Default "vertical"
classNameMerged with the self-stretching separator classes for custom color or spacing.
Type string
childrenPass plain button-like elements as children. Their props and children are hoisted into the internal motion buttons rendered by the group.
Type ReactNode
classNameMerged onto the outer segmented wrapper for width or surface overrides.
Type string
sizeSets the shared height, padding, and typography of the grouped buttons.
Type "sm" | "md" | "lg"·Default "md"
showDividersRemoves 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
disableRippleTurns off the ripple for every internal button rendered by the group.
Type boolean·Default false
optionsOrdered 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 }>
valueControlled selected value. When provided, the internal state syncs to this prop through an effect.
Type string
onChangeCalled with the selected value whenever a segment is pressed or moved to with the keyboard.
Type (value: string) => void
ariaLabelAccessible name for the radiogroup. Provide this or ariaLabelledBy so screen readers can identify the control.
Type string
ariaLabelledByID of an external label element that names the radiogroup. Use when a visible label already exists in the page.
Type string
nameWhen provided, renders a hidden input so the selected value can participate in native form submission.
Type string
disabledDisables the entire control and every segment inside it.
Type boolean·Default false
orientationLayout direction for the segmented shell and the primary arrow-key axis.
Type "horizontal" | "vertical"·Default "horizontal"
classNameMerged onto the segmented wrapper for width, alignment, or spacing overrides.
Type string
layoutIdOptional 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
sizeControls the overall density of the segmented control shell and each segment inside it.
Type "sm" | "md" | "lg"·Default "md"
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.
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.