Button group components

FREE

Free and open-source React button group components built for modern applications and websites. These button groups are built using React Aria and styled with Tailwind CSS.

Installation

You can add this button group component using our CLI or manually:

npx untitledui@latest add button-group

Button group examples

Below are examples and variations of this button group component:

API reference

ButtonGroup

Import ButtonGroup from @/components/base/button-group/button-group. Renders React Aria’s ToggleButtonGroup — all of its props are supported.

ButtonGroup props
PropTypeDefaultDescription
size
"sm""md""lg"
"md"Controls the padding, text size and icon size of every item in the group.
classNamestring—The class name applied to the group wrapper.
Props from react-stately (14)
ButtonGroup inherited props
PropTypeDefaultDescription
defaultSelectedKeysIterable<Key>—The initial selected keys in the collection (uncontrolled).
disallowEmptySelectionboolean—Whether the collection allows empty selection.
isDisabledboolean—Whether all items are disabled.
onSelectionChange((keys: Set<Key>) => void)—Handler that is called when the selection changes.
selectedKeysIterable<Key>—The currently selected keys in the collection (controlled).
selectionMode
"single""multiple"
"single"Whether single or multiple selection is enabled.
styleStyleOrFunction<ToggleButtonGroupRenderProps>—The inline style for the element. A function may be provided to compute the style based on component state.
childrenChildrenOrFunction<ToggleButtonGroupRenderProps>—The children of the component. A function may be provided to alter the children based on component state.
slotstring | null—A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent.
renderDOMRenderFunction<"div", ToggleButtonGroupRenderProps>—Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Requirements:
  • You must render the expected element type (e.g. if <button> is expected, you cannot render an <a>).
  • Only a single root DOM element can be rendered (no fragments).
  • You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.
aria-describedbystring—Identifies the element (or elements) that describes the object.
aria-detailsstring—Identifies the element (or elements) that provide a detailed, extended description for the object.
aria-labelstring—Defines a string value that labels the current element.
aria-labelledbystring—Identifies the element (or elements) that labels the current element.

Also accepts all standard React DOM event handlers, the global HTML attributes (dir, lang, hidden, inert, translate).

ButtonGroupItem

Import ButtonGroupItem from @/components/base/button-group/button-group. Renders React Aria’s ToggleButton — all of its props are supported.

ButtonGroupItem props
PropTypeDefaultDescription
iconLeadingReactNode | FC<{ className?: string; }>—An icon rendered before the label. Passing only an icon with no children renders an icon-only button.
iconTrailingReactNode | FC<{ className?: string; }>—An icon rendered after the label.
onClick(() => void)—Handler called when the button is clicked.
classNamestring—The class name applied to the button.
Props from React Aria (34)
ButtonGroupItem inherited props
PropTypeDefaultDescription
onPress((e: PressEvent) => void)—Handler that is called when the press is released over the target.
onPressChange((isPressed: boolean) => void)—Handler that is called when the press state changes.
onPressEnd((e: PressEvent) => void)—Handler that is called when a press interaction ends, either over the target or when the pointer leaves the target.
onPressStart((e: PressEvent) => void)—Handler that is called when a press interaction starts.
onPressUp((e: PressEvent) => void)—Handler that is called when a press is released over the target, regardless of whether it started on the target or not.
onHoverChange((isHovering: boolean) => void)—Handler that is called when the hover state changes.
onHoverEnd((e: HoverEvent) => void)—Handler that is called when a hover interaction ends.
onHoverStart((e: HoverEvent) => void)—Handler that is called when a hover interaction starts.
onBlur((e: FocusEvent<Element, Element>) => void)—Handler that is called when the element loses focus.
onFocus((e: FocusEvent<Element, Element>) => void)—Handler that is called when the element receives focus.
onFocusChange((isFocused: boolean) => void)—Handler that is called when the element's focus status changes.
autoFocusboolean—Whether the element should receive focus on render.
excludeFromTabOrderboolean—Whether to exclude the element from the sequential tab order. If true, the element will not be focusable via the keyboard by tabbing. This should be avoided except in rare scenarios where an alternative means of accessing the element or its functionality via the keyboard is available.
onKeyDown((e: KeyboardEvent) => void)—Handler that is called when a key is pressed.
onKeyUp((e: KeyboardEvent) => void)—Handler that is called when a key is released.
defaultSelectedboolean—Whether the element should be selected (uncontrolled).
idKey—When used in a ToggleButtonGroup, an identifier for the item in selectedKeys. When used standalone, a DOM id.
isDisabledboolean—Whether the button is disabled.
isSelectedboolean—Whether the element should be selected (controlled).
onChange((isSelected: boolean) => void)—Handler that is called when the element's selection state changes.
preventFocusOnPressboolean—Whether to prevent focus from moving to the button when pressing it.Caution, this can make the button inaccessible and should only be used when alternative keyboard interaction is provided, such as ComboBox's MenuTrigger or a NumberField's increment/decrement control.
styleStyleOrFunction<ToggleButtonRenderProps>—The inline style for the element. A function may be provided to compute the style based on component state.
childrenChildrenOrFunction<T>—The children of the component. A function may be provided to alter the children based on component state.
slotstring | null—A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent.
renderDOMRenderFunction<"button", ToggleButtonRenderProps>—Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Requirements:
  • You must render the expected element type (e.g. if <button> is expected, you cannot render an <a>).
  • Only a single root DOM element can be rendered (no fragments).
  • You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.
aria-describedbystring—Identifies the element (or elements) that describes the object.
aria-detailsstring—Identifies the element (or elements) that provide a detailed, extended description for the object.
aria-labelstring—Defines a string value that labels the current element.
aria-labelledbystring—Identifies the element (or elements) that labels the current element.
aria-controlsstring—Identifies the element (or elements) whose contents or presence are controlled by the current element.
aria-disabled
falsetrue"true""false"
—Indicates whether the element is disabled to users of assistive technology.
aria-expanded
falsetrue"true""false"
—Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed.
aria-haspopup
falsetrue"true""false""menu""listbox""tree""grid""dialog"
—Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by an element.
aria-pressed
falsetrue"true""false""mixed"
—Indicates the current "pressed" state of toggle buttons.

Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.

FAQs

Please refer to our frequently asked questions page for more.

ButtonGroup is built on React Aria's ToggleButtonGroup and defaults to selectionMode "single". Give each ButtonGroupItem an id, then pass selectedKeys and onSelectionChange for controlled state, or defaultSelectedKeys for uncontrolled state. Add disallowEmptySelection if users shouldn't be able to deselect the active item.

Set selectionMode="multiple" on ButtonGroup. Your props are applied after the built-in "single" default, so they override it. selectedKeys then holds every selected item's id.

Each item is a toggle button, so clicking it marks it as selected. To keep a group of plain action buttons, pass selectedKeys={[]} as the examples do, and handle clicks with onPress on each ButtonGroupItem.

Button groups support "sm", "md" and "lg". Set the size prop on ButtonGroup and every ButtonGroupItem inside it picks up that size. The default is "md".

Use the iconLeading and iconTrailing props on ButtonGroupItem. They accept a component reference like iconLeading={Archive} or a React element. If an item has an icon but no children, it switches to icon-only padding, so give it an aria-label for screen readers.

Set isDisabled on ButtonGroup to disable every item, or set isDisabled on an individual ButtonGroupItem to disable only that one. Disabled items render faded with a not-allowed cursor.

The group uses React Aria's toolbar behavior, so Tab moves focus into the group and the arrow keys move focus between items. In "single" selection mode the group is exposed as role="radiogroup" with each item as role="radio"; in "multiple" mode it is a toolbar of toggle buttons.