सामग्री पर जाएँ

बटन समूह

फ्यूज़ स्प्लिट बटन, टूलबार और इनपुट ऐड-ऑन को एक फ्रेमयुक्त इकाई में जोड़ता है — एक मोटी सीमा, एक कठोर छाया, एक साझा दबाव।

"use client"

import * as React from "react"

बटन ग्रुप आस-पास के बटन, इनपुट और लेबल को एक सेगमेंटेड कंट्रोल में जोड़ता है। नीचे कोई प्रिमिटिव नहीं — सादा role="group" कंटेनर नियोब्रूटलिस्ट फ़्रेम रखता है (एक मोटा बॉर्डर, एक कठोर छाया, एक साझा प्रेस एनिमेशन); सिर्फ़ ButtonGroupSeparator प्रिमिटिव लेता है, Separator को रैप करके।

इसे इन स्थितियों में चुनें:

  • स्प्लिट बटन — मुख्य एक्शन के साथ विकल्पों का DropdownMenu: Save / Save as…, Merge / Squash।
  • पेजर और टूलबार — Previous/Next, ज़ूम इन/आउट, व्यू स्विचर एक ही फ़्रेम में।
  • इनपुट ऐड-ऑन — सर्च फ़ील्ड के साथ सबमिट बटन, URL प्रीफ़िक्स लेबल, कॉपी बटन सफ़िक्स।

इंस्टॉलेशन

pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/button-group.json
npx shadcn@latest add https://neobrutalism.com/r/base/button-group.json
yarn dlx shadcn@latest add https://neobrutalism.com/r/base/button-group.json
bunx --bun shadcn@latest add https://neobrutalism.com/r/base/button-group.json

निम्नलिखित डिपेंडेंसी इंस्टॉल करें:

pnpm add @base-ui/react
npm install @base-ui/react
yarn add @base-ui/react
bun add @base-ui/react

निम्नलिखित कोड को कॉपी करके अपने प्रोजेक्ट में पेस्ट करें।

components/ui/button-group.tsx
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"

import { cn } from "@/lib/utils"
import { Separator } from "@/components/ui/separator"

const buttonGroupVariants = cva(
  cn(
    // The GROUP itself is the cohesive NeoBrutalist unit: a single bold border +
    // one hard offset shadow wrapping every segment, so it reads as ONE unit.
    // The frame animates so the whole group can press like a single Button.
    "relative inline-flex w-fit items-stretch border-2 border-foreground bg-background shadow-md transition-all duration-200",
    // Segments become flush fills — the frame owns the border, shadow and corners.
    "[&>*]:rounded-none",
    "[&>:is(button,a)]:border-0 [&>:is(button,a)]:shadow-none!",
    // Segments never translate on their own — only the whole frame moves.
    "[&>:is(button,a)]:hover:translate-y-0! [&>:is(button,a)]:active:translate-x-0! [&>:is(button,a)]:active:translate-y-0!",
    // The WHOLE group presses into its shadow like a single Button: hover sinks it
    // toward the shadow, press sits it flush (shadow gone).
    "has-[:is(button,a):hover]:translate-y-1 has-[:is(button,a):hover]:shadow",
    "has-[:is(button,a):active]:translate-y-2 has-[:is(button,a):active]:translate-x-1 has-[:is(button,a):active]:shadow-none",
    // When a group CONTAINS nested groups it becomes a plain gapped container
    // (no frame / shadow / press) so each nested sub-group is its own pressable
    // unit instead of pressing the whole outer frame.
    "has-[>[data-slot=button-group]]:gap-2 has-[>[data-slot=button-group]]:border-0 has-[>[data-slot=button-group]]:bg-transparent has-[>[data-slot=button-group]]:shadow-none! has-[>[data-slot=button-group]]:translate-x-0! has-[>[data-slot=button-group]]:translate-y-0!",
    // The hovered/pressed segment darkens in place via a full-bleed inset tint, so
    // you can still tell which segment you're acting on while the frame presses.
    "[&>:is(button,a):hover]:shadow-[inset_0_0_0_999px_#00000012]! [&>:is(button,a):active]:shadow-[inset_0_0_0_999px_#0000001f]!",

    "dark:[&>:is(button,a):hover]:shadow-[inset_0_0_0_999px_#ffffff1f]! dark:[&>:is(button,a):active]:shadow-[inset_0_0_0_999px_#ffffff33]!",
    // Solid dark segments (secondary) always lighten on hover — a dark tint would
    // be invisible on a black button in light mode.
    "[&>:is(button,a)[data-variant=secondary]:hover]:shadow-[inset_0_0_0_999px_#ffffff2b]! [&>:is(button,a)[data-variant=secondary]:active]:shadow-[inset_0_0_0_999px_#ffffff45]!",
    "[&>:is(button,a):focus-visible]:relative [&>:is(button,a):focus-visible]:z-10"
  ),
  {
    variants: {
      orientation: {
        // A single crisp seam between segments (logical side, so RTL-correct).
        horizontal:
          "flex-row [&>*:not(:first-child)]:border-s-2! [&>*:not(:first-child)]:border-foreground",
        vertical:
          "flex-col [&>*:not(:first-child)]:border-t-2! [&>*:not(:first-child)]:border-foreground",
      },
    },
    defaultVariants: {
      orientation: "horizontal",
    },
  }
)

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

function ButtonGroupText({
  className,
  asChild = false,
  ...props
}: React.ComponentProps<"div"> & {
  asChild?: boolean
}) {
  const Comp = asChild ? Slot.Root : "div"

  return (
    <Comp
      data-slot="button-group-text"
      className={cn(
        "inline-flex items-center gap-2 bg-muted px-3 font-head text-sm font-medium text-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
        className
      )}
      {...props}
    />
  )
}

function ButtonGroupSeparator({
  className,
  orientation = "vertical",
  ...props
}: React.ComponentProps<typeof Separator>) {
  return (
    <Separator
      data-slot="button-group-separator"
      orientation={orientation}
      className={cn(
        "relative z-10 self-stretch bg-border data-horizontal:h-0.5 data-horizontal:w-auto data-vertical:h-auto data-vertical:w-0.5",
        className
      )}
      {...props}
    />
  )
}

export {
  ButtonGroup,
  ButtonGroupSeparator,
  ButtonGroupText,
  buttonGroupVariants,
}

अपने प्रोजेक्ट सेटअप से मेल खाने के लिए import पाथ अपडेट करें।

उपयोग

import {
  ButtonGroup,
  ButtonGroupSeparator,
  ButtonGroupText,
} from "@/components/ui/button-group"
<ButtonGroup>
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</ButtonGroup>

कंपोज़िशन

ButtonGroup बनाने के लिए निम्नलिखित कंपोज़िशन का उपयोग करें:

ButtonGroup
├── Button or Input
├── ButtonGroupSeparator
└── ButtonGroupText

एक्सेसिबिलिटी

  • ButtonGroup कंपोनेंट में role एट्रिब्यूट group पर सेट होता है।
  • ग्रुप के बटन के बीच नेविगेट करने के लिए Tab का उपयोग करें।
  • बटन ग्रुप को लेबल करने के लिए aria-label या aria-labelledby का उपयोग करें।
<ButtonGroup aria-label="Button group">
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</ButtonGroup>

ButtonGroup vs ToggleGroup

  • जब आप ऐसे बटन ग्रुप करना चाहें जो कोई एक्शन करते हैं, तब ButtonGroup कंपोनेंट का उपयोग करें।
  • जब आप ऐसे बटन ग्रुप करना चाहें जो किसी स्टेट को टॉगल करते हैं, तब ToggleGroup कंपोनेंट का उपयोग करें।

उदाहरण

ओरिएंटेशन

बटन ग्रुप का लेआउट बदलने के लिए orientation prop सेट करें।

import { MinusIcon, PlusIcon } from "lucide-react"

import { Button } from "@/components/ui/button"

साइज़

अलग-अलग बटन पर size prop का उपयोग करके बटन का साइज़ नियंत्रित करें।

import { PlusIcon } from "lucide-react"

import { Button } from "@/components/ui/button"

नेस्टेड

स्पेसिंग वाले बटन ग्रुप बनाने के लिए <ButtonGroup> कंपोनेंट को नेस्ट करें।

import { AudioLinesIcon, PlusIcon } from "lucide-react"

import { Button } from "@/components/ui/button"

सेपरेटर

ButtonGroupSeparator कंपोनेंट किसी ग्रुप के भीतर बटन को दृश्य रूप से विभाजित करता है।

outline वेरिएंट वाले बटन को सेपरेटर की ज़रूरत नहीं होती, क्योंकि उनमें पहले से बॉर्डर होता है। अन्य वेरिएंट के लिए, विज़ुअल पदानुक्रम बेहतर करने हेतु सेपरेटर की सलाह दी जाती है।

import { Button } from "@/components/ui/button"
import {
  ButtonGroup,

स्प्लिट

ButtonGroupSeparator से अलग किए गए दो बटन जोड़कर एक स्प्लिट बटन ग्रुप बनाएँ।

import { IconPlus } from "@tabler/icons-react"

import { Button } from "@/components/ui/button"

Input

किसी Input कंपोनेंट को बटन के साथ रैप करें।

import { SearchIcon } from "lucide-react"

import { Button } from "@/components/ui/button"

Input Group

जटिल इनपुट लेआउट बनाने के लिए किसी InputGroup कंपोनेंट को रैप करें।

"use client"

import * as React from "react"

किसी DropdownMenu कंपोनेंट के साथ एक स्प्लिट बटन ग्रुप बनाएँ।

"use client"

import {

Select

किसी Select कंपोनेंट के साथ जोड़ें।

"use client"

import * as React from "react"

Popover

किसी Popover कंपोनेंट के साथ उपयोग करें।

import { BotIcon, ChevronDownIcon } from "lucide-react"

import { Button } from "@/components/ui/button"

RTL

Neobrutalism में RTL सपोर्ट सक्षम करने के लिए, RTL कॉन्फ़िगरेशन गाइड देखें।

"use client"

import * as React from "react"

एक्सेसिबिलिटी

ButtonGroup role="group" रेंडर करता है, जिससे असिस्टिव टेक को पता चलता है कि बटन एक साथ हैं, बिना कीबोर्ड व्यवहार बदले — हर बटन अपना टैब स्टॉप और नेटिव Enter / Space ऐक्टिवेशन रखता है। ग्रुप को aria-label या aria-labelledby से नाम दें ताकि स्क्रीन रीडर संदर्भ घोषित करें:

<ButtonGroup aria-label="Pagination">
  <Button>Previous</Button>
  <Button>Next</Button>
</ButtonGroup>

ButtonGroupSeparator Base UI Separator को रैप करता है, जो मिलते aria-orientation के साथ role="separator" रेंडर करता है — डिवाइडर के रूप में घोषित, कभी फ़ोकस-योग्य नहीं। अगर बटनों के बीच एरो-कुंजी नेविगेशन वाला एक टैब स्टॉप चाहिए, तो वह WAI-ARIA Toolbar पैटर्न है — यह कंपोनेंट जानबूझकर सादा टैब क्रम रखता है।

API रेफ़रेंस

ButtonGroup

ButtonGroup कंपोनेंट एक कंटेनर है, जो संबंधित बटन को एक जैसी स्टाइल के साथ एक साथ ग्रुप करता है।

PropTypeDefault
orientation"horizontal" | "vertical""horizontal"
<ButtonGroup>
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</ButtonGroup>

स्पेसिंग वाले जटिल लेआउट बनाने के लिए कई बटन ग्रुप नेस्ट करें। अधिक जानकारी के लिए नेस्टेड उदाहरण देखें।

<ButtonGroup>
  <ButtonGroup />
  <ButtonGroup />
</ButtonGroup>

ButtonGroupSeparator

ButtonGroupSeparator कंपोनेंट किसी ग्रुप के भीतर बटन को दृश्य रूप से विभाजित करता है।

PropTypeDefault
orientation"horizontal" | "vertical""vertical"
<ButtonGroup>
  <Button>Button 1</Button>
  <ButtonGroupSeparator />
  <Button>Button 2</Button>
</ButtonGroup>

ButtonGroupText

किसी बटन ग्रुप के भीतर टेक्स्ट दिखाने के लिए इस कंपोनेंट का उपयोग करें।

PropTypeDefault
asChildbooleanfalse
<ButtonGroup>
  <ButtonGroupText>Text</ButtonGroupText>
  <Button>Button</Button>
</ButtonGroup>

टेक्स्ट के रूप में कोई कस्टम कंपोनेंट रेंडर करने के लिए asChild prop का उपयोग करें, उदाहरण के लिए एक label।

import { ButtonGroupText } from "@/components/ui/button-group"
import { Label } from "@/components/ui/label"
 
export function ButtonGroupTextDemo() {
  return (
    <ButtonGroup>
      <ButtonGroupText asChild>
        <Label htmlFor="name">Text</Label>
      </ButtonGroupText>
      <Input placeholder="Type something here..." id="name" />
    </ButtonGroup>
  )
}