Button Group

A container that groups related buttons together with consistent styling.

ButtonGroupExample

Examples

Orientation

Set orientation="vertical" to stack buttons instead of placing them in a row.

ButtonGroupOrientationExample

Separator

Use ButtonGroupSeparator to visually divide buttons. The outline variant already has borders, so separators are most useful for solid variants.

ButtonGroupSeparatorExample

Text

Use ButtonGroupText for static prefixes and suffixes, and mix in an Input to build composed fields.

ButtonGroupTextExample
https://

Nested

Nest multiple ButtonGroup components to add spacing between clusters of related actions.

ButtonGroupNestedExample

Installation

Copy the source code below into your project:

tsx
import { mergeProps, useRender } from "@base-ui/react";
import { Separator } from "./separator";
import { cn } from "@/lib/utils";
import { cva } from "class-variance-authority";
import type { ComponentProps } from "react";
import type { VariantProps } from "class-variance-authority";

const buttonGroupVariants = cva(
  "flex w-fit items-stretch has-[>[data-slot=button-group]]:gap-2 [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
  {
    defaultVariants: {
      orientation: "horizontal",
    },
    variants: {
      orientation: {
        horizontal:
          "[&>*:not(:first-child)]:-ms-px [&>*:not(:first-child)]:rounded-l-none [&>*:not(:last-child)]:rounded-r-none",
        vertical:
          "flex-col [&>*:not(:first-child)]:-mt-px [&>*:not(:first-child)]:rounded-t-none [&>*:not(:last-child)]:rounded-b-none",
      },
    },
  },
);

function ButtonGroup({
  className,
  orientation = "horizontal",
  ...props
}: ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
  return (
    <div
      className={cn(buttonGroupVariants({ orientation }), className)}
      data-orientation={orientation}
      data-slot="button-group"
      role="group"
      {...props}
    />
  );
}

function ButtonGroupText({ className, render, ...props }: useRender.ComponentProps<"div">) {
  return useRender({
    defaultTagName: "div",
    props: {
      ...mergeProps<"div">(props, {
        className: cn(
          "flex items-center gap-2 rounded-lg border border-input bg-muted px-4 text-sm font-medium text-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
          className,
        ),
      }),
      "data-slot": "button-group-text",
    },
    render,
  });
}

function ButtonGroupSeparator({
  className,
  orientation = "vertical",
  ...props
}: ComponentProps<typeof Separator>) {
  return (
    <Separator
      className={cn(
        "relative m-0! self-stretch bg-border data-[orientation=vertical]:h-auto",
        className,
      )}
      data-slot="button-group-separator"
      orientation={orientation}
      {...props}
    />
  );
}

export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants };

API Reference

ButtonGroup

PropTypeDefaultDescription
orientation"horizontal" | "vertical""horizontal"Layout direction of the grouped buttons.

ButtonGroupSeparator

The ButtonGroupSeparator component extends the Ink UI Separator props and adds the following:

PropTypeDefaultDescription
orientation"horizontal" | "vertical""vertical"Orientation of the separator within the group.

ButtonGroupText

PropTypeDefaultDescription
renderReactElement | ((props, state) => ReactElement)-Render the text as a custom element instead of a div.