Button Group

Segmented button rows and compact icon actions with a smoother shared motion treatment.

Live Playground

Inspect the segmented row and the compact icon action you pointed at, with the updated hover motion and softer settling behavior.

The segmented row keeps the same bordered shell while the hover surface glides smoothly between items.

The icon button now uses a softer lift and calmer icon settle on hover instead of the sharper bounce.

Install And Iterate

Install the component directly into your codebase, then branch into v0 if you want to iterate on variations.

Install

npx shadcn@latest add @iconiq/button-group

Build with v0

Send the registry bundle into v0 when you want to explore new colorways, copy, or layout directions quickly.

Notes

  • ButtonGroupItems is best when you want a single bordered shell shared across several adjacent actions.
  • IconButton uses the same surface language in a smaller square control for compact toolbar actions.

Usage

Use the segmented row for adjacent view switches, then pair it with icon-only actions when you need a smaller utility control.

"use client"; import { Bell, Grid2x2, List, Table2 } from "lucide-react";import { ButtonGroupItems, IconButton } from "@/components/ui/button-group"; export function ViewControls() {  return (    <div className="space-y-6">      <ButtonGroupItems>        <button type="button">          <List className="size-4" />          List        </button>        <button type="button">          <Grid2x2 className="size-4" />          Board        </button>        <button type="button">          <Table2 className="size-4" />          Table        </button>      </ButtonGroupItems>       <IconButton aria-label="Notifications" type="button">        <Bell className="size-4" />      </IconButton>    </div>  );}

API Details

Each item below covers the documented props and the behavior that matters during implementation.

Button

2 props

Standalone motion button with a light upward entrance, hover scale, and a small label nudge inside the content span.
childrenReactNode
Required
Button content rendered inside an animated inline span so the label can shift slightly on hover.
classNamestring
Merged onto the root button. Use it for local width, spacing, or surface overrides.

Notes

Most standard button props such as type, disabled, onClick, name, value, aria-*, and data-* are forwarded to the underlying motion button.
The public prop surface intentionally leaves out the native drag and CSS animation callback props because they conflict with Motion's own handler names.

IconButton

2 props

Compact icon-only version of the same button surface, with a stronger hover scale and a rotating inner icon span.
childrenReactNode
Required
Icon content rendered inside the motion span. SVG children inherit the built-in 1rem sizing utility.
classNamestring
Merged onto the icon button root for size or surface overrides.

ButtonGroup

2 props

Simple flex wrapper for arranging several button surfaces in one row with shared staggered entrance motion.
childrenReactNode
Required
Buttons, icon buttons, or any other inline controls you want to keep in the same row.
classNamestring
Merged onto the outer motion div. The base layout already applies a horizontal flex row with a small gap.

ButtonGroupItems

2 props

Segmented button shell that turns each valid child element into an internal motion button with shared borders and equal visual rhythm.
childrenReactNode
Required
Pass plain button-like elements as children. Their props and children are hoisted into the internal motion buttons rendered by the group.
classNamestring
Merged onto the outer segmented wrapper for width or surface overrides.

Notes

Only valid React elements are rendered. Non-element children are ignored.
The child node itself is not preserved; ButtonGroupItems reads each child's props and children, then renders a fresh motion button for that slot.

SegmentedControl

5 props

String-based segmented selector with internal state support, hover wash, and a spring-driven selected indicator.
optionsstring[]
Required
Ordered list of visible segments. The first option becomes the uncontrolled initial selection when value is not provided.
valuestring
Controlled selected option. When provided, the internal state syncs to this prop through an effect.
onChange(value: string) => void
Called with the selected option whenever a segment is pressed.
classNamestring
Merged onto the segmented wrapper for width, alignment, or spacing overrides.
layoutIdstring
Default"segmented-indicator"
Motion layout id used by the selected indicator. Override it when you render multiple segmented controls on the same page and want isolated indicator motion.