#6516·heroui

[BUG] - ButtonGroup variant/size props don't propagate to Button when child is wrapped in Tooltip

Author: rakibatomniximaCreated May 13, 2026Updated Jul 29, 2026

HeroUI Version

@heroui/[email protected]

Describe the bug

ButtonGroup propagates variant, size, isDisabled, and fullWidth to its child Buttons via two mechanisms in tandem:

  1. A ButtonGroupContext provider.
  2. A __button_group_child: true marker prop stamped onto direct children via Children.map + cloneElement (packages/components/button-group/src/button-group.tsx).

Button then gates context consumption behind that marker:

javascript
// packages/components/button/src/button.tsx
const shouldUseContext = isButtonGroupChild === true;
const finalVariant = variant ?? (shouldUseContext ? buttonGroupContext?.variant : undefined);

When a Button is wrapped in any single-element passthrough — most commonly <Tooltip>, but also things like <Popover.Trigger> — the wrapper becomes the direct child of ButtonGroup and absorbs the marker (Tooltip silently drops unknown props). The inner Button never receives the marker, shouldUseContext stays false, and variant / size / isDisabled / fullWidth fall back to component defaults instead of inheriting from the group.

The sibling pair behaves differently: ToggleButtonGroup exports TOGGLE_BUTTON_GROUP_CHILD but never references it (dead code in toggle-button-group.tsx), and ToggleButton reads ToggleButtonGroupContext unconditionally with no marker gate. So the exact same Tooltip wrap works for ToggleButton.

Stamps marker on direct children? Reads context conditionally?
ButtonGroup + Button yes gated on __button_group_child === true
ToggleButtonGroup + ToggleButton declares marker constant, never uses it reads context unconditionally

Your Example Website or App

Reproduces locally on the v3 starter; happy to put together a Stackblitz if helpful.

Steps to Reproduce the Bug or Issue

typescript
import { Button, ButtonGroup, Tooltip, ToggleButton, ToggleButtonGroup } from '@heroui/react';

// Works — Button inherits "secondary" variant from ButtonGroup
<ButtonGroup variant="secondary">
  <Button>A</Button>
  <Button>B</Button>
</ButtonGroup>

// Broken — Buttons render with their own default variant, not "secondary"
<ButtonGroup variant="secondary">
  <Tooltip content="Tip A"><Button>A</Button></Tooltip>
  <Tooltip content="Tip B"><Button>B</Button></Tooltip>
</ButtonGroup>

// Works — ToggleButton reads its group's context unconditionally
<ToggleButtonGroup>
  <Tooltip content="Tip A"><ToggleButton>A</ToggleButton></Tooltip>
  <Tooltip content="Tip B"><ToggleButton>B</ToggleButton></Tooltip>
</ToggleButtonGroup>
  1. Render a ButtonGroup with variant="secondary" (or any non-default value).
  2. Wrap each child Button in a <Tooltip>.
  3. Observe that the Buttons render with the default variant instead of "secondary".
  4. Swap Button / ButtonGroup for ToggleButton / ToggleButtonGroup — propagation works.

Expected behavior

Wrapping a Button in <Tooltip> (or any other transparent single-element wrapper) shouldn't sever ButtonGroup → Button propagation. The natural fixes are either:

  • Have Button consume ButtonGroupContext unconditionally — mirrors ToggleButton's existing behavior and removes the asymmetry. The risk is that this resurfaces #2142 (Buttons rendered through Modals/Portals from inside a ButtonGroup would inherit group styling, since React context crosses portal boundaries).
  • Have ButtonGroup recurse the marker through known transparent wrappers (Tooltip, Popover.Trigger, etc.) when cloning children — keeps #2142 fixed but requires a wrapper allowlist or a heuristic ("element with a single React element child").
  • Have transparent wrappers (Tooltip etc.) forward unknown props to their first child — standard "transparent forwarding" pattern; handles arbitrary marker props without ButtonGroup needing to know about wrappers.

Screenshots or Videos

n/a

Operating System Version

macOS

Browser

Chrome