# HeroUI Button Group

> HeroUI-style group with solid/bordered/flat/faded variants, 4 semantic colors and configurable radius.

- Author: Atelier UI
- License: MIT
- Page: https://chromotion.dev/en/components/heroui-button-group
- Site: Atelier UI (https://chromotion.dev)

## Install

```bash
npx shadcn@latest add https://chromotion.dev/r/heroui-button-group.json
```

Stack: React + TypeScript + Tailwind CSS v4, shadcn/ui conventions. `cn` comes from `@/lib/utils`.

## Dependencies

No extra dependencies.

## Usage

```tsx title="components/heroui-button-group-demo.tsx"
import { HeroUIButtonGroup, HeroUIButtonGroupItem } from "@/components/heroui-button-group"

const variants = ["solid", "bordered", "flat", "faded"] as const

export default function HeroUIButtonGroupDemo() {
  return (
    <div className="flex flex-col items-center gap-4 p-8">
      {variants.map((variant) => (
        <HeroUIButtonGroup key={variant} variant={variant} color="primary" aria-label={variant}>
          <HeroUIButtonGroupItem>One</HeroUIButtonGroupItem>
          <HeroUIButtonGroupItem>Two</HeroUIButtonGroupItem>
          <HeroUIButtonGroupItem>Three</HeroUIButtonGroupItem>
        </HeroUIButtonGroup>
      ))}
      <HeroUIButtonGroup variant="flat" color="danger" radius="full" aria-label="Pill">
        <HeroUIButtonGroupItem>Pill</HeroUIButtonGroupItem>
        <HeroUIButtonGroupItem>Shaped</HeroUIButtonGroupItem>
      </HeroUIButtonGroup>
    </div>
  )
}
```

## Source

```tsx title="components/heroui-button-group.tsx"
"use client"

import * as React from "react"

import { cn } from "@/lib/utils"

type Variant = "solid" | "bordered" | "flat" | "faded"
type Color = "default" | "primary" | "success" | "danger"
type Radius = "none" | "sm" | "md" | "lg" | "full"

const styles: Record<Variant, Record<Color, string>> = {
  solid: {
    default: "bg-zinc-200 text-zinc-900 hover:bg-zinc-300 dark:bg-zinc-700 dark:text-zinc-100 dark:hover:bg-zinc-600",
    primary: "bg-blue-600 text-white hover:bg-blue-700",
    success: "bg-green-500 text-white hover:bg-green-600",
    danger: "bg-red-500 text-white hover:bg-red-600",
  },
  bordered: {
    default: "border-2 border-zinc-300 text-zinc-700 hover:bg-zinc-100 dark:border-zinc-600 dark:text-zinc-200 dark:hover:bg-zinc-800",
    primary: "border-2 border-blue-500 text-blue-600 hover:bg-blue-500/10 dark:text-blue-400",
    success: "border-2 border-green-500 text-green-600 hover:bg-green-500/10 dark:text-green-400",
    danger: "border-2 border-red-500 text-red-600 hover:bg-red-500/10 dark:text-red-400",
  },
  flat: {
    default: "bg-zinc-200/70 text-zinc-700 hover:bg-zinc-200 dark:bg-zinc-700/60 dark:text-zinc-200 dark:hover:bg-zinc-700",
    primary: "bg-blue-500/20 text-blue-600 hover:bg-blue-500/30 dark:text-blue-400",
    success: "bg-green-500/20 text-green-700 hover:bg-green-500/30 dark:text-green-400",
    danger: "bg-red-500/20 text-red-600 hover:bg-red-500/30 dark:text-red-400",
  },
  faded: {
    default: "border-2 border-zinc-200 bg-zinc-100 text-zinc-800 hover:bg-zinc-200 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-700",
    primary: "border-2 border-zinc-200 bg-zinc-100 text-blue-600 hover:bg-zinc-200 dark:border-zinc-700 dark:bg-zinc-800 dark:text-blue-400 dark:hover:bg-zinc-700",
    success: "border-2 border-zinc-200 bg-zinc-100 text-green-600 hover:bg-zinc-200 dark:border-zinc-700 dark:bg-zinc-800 dark:text-green-400 dark:hover:bg-zinc-700",
    danger: "border-2 border-zinc-200 bg-zinc-100 text-red-600 hover:bg-zinc-200 dark:border-zinc-700 dark:bg-zinc-800 dark:text-red-400 dark:hover:bg-zinc-700",
  },
}

const radii: Record<Radius, string> = {
  none: "rounded-none",
  sm: "rounded-md",
  md: "rounded-lg",
  lg: "rounded-xl",
  full: "rounded-full",
}

interface GroupContextValue {
  variant: Variant
  color: Color
}

const GroupContext = React.createContext<GroupContextValue>({ variant: "solid", color: "default" })

export interface HeroUIButtonGroupProps extends React.ComponentProps<"div"> {
  variant?: Variant
  color?: Color
  radius?: Radius
}

export function HeroUIButtonGroup({
  variant = "solid",
  color = "default",
  radius = "md",
  className,
  ...props
}: HeroUIButtonGroupProps) {
  const value = React.useMemo(() => ({ variant, color }), [variant, color])

  return (
    <GroupContext.Provider value={value}>
      <div role="group" className={cn("inline-flex overflow-hidden", radii[radius], className)} {...props} />
    </GroupContext.Provider>
  )
}

export function HeroUIButtonGroupItem({ className, ...props }: React.ComponentProps<"button">) {
  const { variant, color } = React.useContext(GroupContext)

  return (
    <button
      className={cn(
        "inline-flex h-10 items-center justify-center gap-2 rounded-none px-5 text-sm font-medium transition-colors",
        "focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none focus-visible:ring-inset",
        "disabled:pointer-events-none disabled:opacity-50 not-first:border-l not-first:border-l-background/40",
        styles[variant][color],
        className
      )}
      {...props}
    />
  )
}
```
