Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Buttons & Actions

Button Group

Buttons & Actions

Button Group React component for Tailwind CSS v4

ButtonCopy Button
Live props
Layout
orientation
attached
fullWidth
Appearance
size
variant
tone
radius
color
State
disabled
Content
aria-label
Code
import { ButtonGroup } from "@/components/ui/button-group"

<ButtonGroup />
  1. Home
  2. Components
  3. Buttons & Actions
  4. Button Group
Pro

Button Group React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A React button group: buttons joined into one control or spaced in a row, plus a split button that pairs a main action with a menu.

Each button presses on its own spring inside the shared shape, and a focused one rises above its neighbours so the ring is never cut off. Tab moves from button to button. The chevron half of a split button opens its menu with a click, Enter, Space or ArrowDown, and turns while open; on a phone the menu arrives as an action sheet. Size, variant, tone, radius and color set on the group flow into every button that did not set its own.

Button Group is a Pro React component in the React button components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add button-group, together with Button, Dropdown Menu, Tones and UIProvider and the npm package lucide-react.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add button-group

Button Group is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import ButtonGroup from @/components/ui/button-group.

import { Eye, Share2 } from "lucide-react"
import { Button } from "@/components/ui/button"
import { ButtonGroup, SplitButton } from "@/components/ui/button-group"

export function PublishBar({ onPublish }: { onPublish: () => void }) {
  return (
    <div className="flex flex-wrap items-center gap-2">
      <ButtonGroup aria-label="Preview and share">
        <Button leftIcon={<Eye />}>Preview</Button>
        <Button leftIcon={<Share2 />}>Share</Button>
      </ButtonGroup>
      <SplitButton
        tone="brand"
        onClick={onPublish}
        menuLabel="More publish options"
        menuProps={{ title: "Publish listing" }}
        items={[
          { label: "Save as draft" },
          { label: "Schedule publishing…" },
          { label: "Publish and duplicate" },
        ]}
      >
        Publish listing
      </SplitButton>
    </div>
  )
}

Props

  • children
    ReactNode

    Buttons, SplitButtons, ButtonGroupText cells and ButtonGroupSeparators. Other elements (a DropdownMenu with a Button trigger) still attach, but do not inherit the group's props: set them on the trigger.

  • orientationdefault "horizontal"
    "horizontal" | "vertical"

    A row, or a stack of full-width buttons (stacked actions on a phone).

  • attacheddefault true
    boolean

    Joined edges: inner corners squared, borders collapsed, dividers between solid, soft and ghost buttons, one shadow for the whole group. Off, the buttons sit in a spaced row (gap-2).

  • sizedefault "md"
    "sm" | "md" | "lg"

    Passed to every child that did not set one. Icon buttons stay square and follow along (sm becomes icon-sm, lg icon-lg). md grows to 44px on touch.

  • variantdefault "outline"
    "solid" | "soft" | "outline" | "ghost"

    Passed down. outline is the classic joined group; solid gets 1px dividers in the text color.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    Passed down to every button.

  • radiusdefault "md"
    "none" | "sm" | "md" | "lg" | "full"

    Passed down; it is the outer shape of the whole group (full makes a pill).

  • colordefault ""
    string

    Any CSS color, passed down in place of the tone. Leave empty to use the tone.

  • disableddefault false
    boolean

    Disables every child that did not set disabled itself.

  • fullWidthdefault false
    boolean

    The group fills its container and the buttons share the width. Made for phone footers.

  • aria-labeldefault ""
    string

    The group's accessible name (role="group"). The playground falls back to a sample name when empty.

  • className
    string

    Extra classes for the group, merged last. Other props go to the root div.

Parts

  • SplitButton

    component

    A main action joined to a chevron that opens a dropdown menu. Takes the Button props for its main half (onClick, leftIcon, loading, loadingText, disabled) plus items: MenuEntry[], menuLabel (default "More options"), menuIcon (default ChevronDown), align ("end") and side ("bottom"), menuProps for the rest of the menu (title of the phone sheet, responsive, shortcut) and fullWidth. The phone sheet is named after a string label unless menuProps sets one. Inside a full-width or vertical group it stretches its main half. variant / tone / size / radius / color default to solid / neutral / md / md and style both halves; loading disables the menu too. Props: SplitButtonProps.

  • ButtonGroupText

    component

    A non-interactive cell with a button's height, padding and type, for units and counters ("USD", "3 / 12"). Inherits from the group like a button. Props: ComponentProps<"div"> & { size, variant, tone, radius, color, disabled }.

  • ButtonGroupSeparator

    component

    An explicit extra break (a 1px line). Pass the group's orientation. Not needed between buttons: the attached group draws its own dividers. Props: ComponentProps<"div"> & { orientation?: "horizontal" | "vertical" }.

Examples

Attached and spaced

Joined into one shape or a spaced row, horizontal or stacked.

Pagination

Icon buttons around a ButtonGroupText counter.

Quantity and units

A pill stepper and a price with its currency cell.

Solid with dividers

One shadow for the group and a 1px divider in the text color between buttons.

Split buttons

Three sizes, an outline one, and loading, which blocks the menu too. On a phone the menu is a sheet.

Phone footer

fullWidth shares the width between the buttons; a vertical group stacks actions, split buttons included.

Custom color

Any CSS color flows into every button of the group.

Dependencies

lucide-reactbuttondropdown-menutonesui-config

Files

  • components/ui/button-group.tsx

FAQ

Is the React Button Group component free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install Button Group?

Run npx wingo-ui@latest add button-group. It also adds the Wingo UI items it builds on (Button, Dropdown Menu, Tones and UIProvider) and the npm package lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/button-group.

How does Button Group behave on phones?

The chevron half of a split button opens its menu with a click, Enter, Space or ArrowDown, and turns while open; on a phone the menu arrives as an action sheet.

See also

ButtonDropdown MenuToggle GroupSegmented Control

More React button components

Copy ButtonTheme ToggleDelete ButtonToggle
All 7 React button components
PreviousButtonNext Copy Button

Linus Roadster city bike

Draft · saved 2 min ago