Bloom Logo

Button Group

ButtonGroup allows grouping multiple buttons together, creating a visually connected set. Propagates variants, colors, sizes, loading, and disabled states to child buttons.

buttonGroup.tsx

Implementation of the ButtonGroup component, managing layout logic and propagating visual traits to children buttons.

ReactTailwindUI ComponentLayoutButtonGroup
"use client";

import * as React from "react";
import { cn } from "@/lib/utils";
import type { ButtonProps } from "../button/button";

export type ButtonGroupProps = {
  children: React.ReactNode;
  variant?: ButtonProps["variant"];
  color?: ButtonProps["color"];
  size?: ButtonProps["size"];
  radius?: ButtonProps["radius"];
  isLoading?: boolean;
  isDisabled?: boolean;
  ariaLabel?: string;
  className?: string;
};

export const ButtonGroup = React.memo(
  ({
    children,
    variant,
    color,
    size,
    radius,
    isLoading,
    isDisabled,
    ariaLabel,
    className,
  }: ButtonGroupProps) => {
    const childrenArray = React.Children.toArray(children);
    const count = childrenArray.length;

    const clonedChildren = React.useMemo(() => {
      return childrenArray.map((child, index) => {
        if (!React.isValidElement<ButtonProps>(child)) return child;

        const isFirst = index === 0;
        const isLast = index === count - 1;

        return React.cloneElement(child, {
          variant: child.props.variant || variant,
          color: child.props.color || color,
          size: child.props.size || size,
          radius: child.props.radius || radius,
          isLoading: child.props.isLoading !== undefined ? child.props.isLoading : isLoading,
          isDisabled: child.props.isDisabled !== undefined ? child.props.isDisabled : isDisabled,
          className: cn(
            child.props.className,
            "rounded-none",
            "focus-visible:z-10 focus-visible:relative",
            isFirst && "rounded-l-xl",
            isLast && "rounded-r-xl",
            !isFirst && !isLast && "-ml-px"
          ),
        });
      });
    }, [childrenArray, variant, color, size, radius, isLoading, isDisabled, count]);

    return (
      <div
        role="group"
        aria-label={ariaLabel}
        className={cn("inline-flex items-center", className)}
      >
        {clonedChildren}
      </div>
    );
  }
);

ButtonGroup.displayName = "ButtonGroup";

Default

A standard connected button group propagating default styling to its child buttons.

Variants

Defines the visual style of each button inside the group via the variant prop.

variant: default | bordered | light | flat | ghost | shadow | link
variant="default"
variant="bordered"
variant="flat"

Colors

Defines the color theme of all buttons inside the group via the color prop. Stacked vertically for clear visual comparison.

color: default | primary | secondary | accent | success | warning | danger
color="default"
color="primary"
color="secondary"
color="accent"
color="success"
color="warning"
color="danger"

Sizes

Adjusts the size scale of each button in the group using the size prop.

size: xs | sm | md | lg | xl | 2xl | 3xl
size="sm"
size="md"
size="lg"

Loading state (isLoading)

Pass isLoading to ButtonGroup to propagate active loading spinners across all buttons in the group.

isLoading: boolean

Disabled state (isDisabled)

Pass isDisabled to ButtonGroup to disable interaction for all buttons in the group.

isDisabled: boolean

Icon Only

Supports icon-only buttons grouped together seamlessly.

isIconOnly: booleanariaLabel: string
API Reference

Props — ButtonGroup

Properties to configure the ButtonGroup container.

PropTypeDefaultDescription
variant'default' | 'bordered' | 'light' | 'flat' | 'ghost' | 'shadow' | 'link'Applies visual style variant to all child buttons.
color'default' | 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'danger'Applies color theme to all child buttons.
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'Applies size scale to all child buttons.
isLoadingbooleanfalsePropagates loading spinners and disables interaction across all buttons.
isDisabledbooleanfalseDisables interaction across all buttons in the group.
ariaLabelstringAccessible label describing the purpose of the group for screen readers.