> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ButtonGroup

> Group related buttons with shared appearance and an optional frame.

export const StoryEmbed = ({storyId, title, height = 240}) => <>
    <Tabs>
      <Tab title="Light">
        <iframe title={`${title} (light)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:light`} width="100%" height={height} loading="lazy" style={{
  border: 0
}} />
      </Tab>
      <Tab title="Dark">
        <iframe title={`${title} (dark)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:dark`} width="100%" height={height} loading="lazy" style={{
  border: 0
}} />
      </Tab>
    </Tabs>
    <a href={`https://storybook.twenty.com/?path=/story/${storyId}`}>
      Open in Storybook
    </a>
  </>;

Give a group an accessible name and place related buttons inside it. The group joins adjacent borders and can apply a shared size, variant, and color. Buttons retain their own tab stops.

## State ownership

`ButtonGroup` coordinates appearance, not selection. It has no controlled or uncontrolled selection mode. Each button receives its own action handler and application state; see [Button's state ownership example](/ui/primitives/input/button#state-ownership) for loading behavior.

For a mutually exclusive choice, use [RadioGroup](/ui/primitives/input/radio-group), which owns selection for its radio controls.

## Usage

```tsx theme={null}
import { Button, ButtonGroup } from 'twenty-ui/primitives/input';

export const RecordActions = () => (
  <ButtonGroup aria-label="Record actions" size="sm">
    <Button>Edit</Button>
    <Button>Duplicate</Button>
  </ButtonGroup>
);
```

## Props

<ParamField body="attached" type="boolean" default="true">
  Join adjacent controls. Set to false for independently rounded buttons with a 2px gap.
</ParamField>

<ParamField body="color" type="&#x22;accent&#x22; | &#x22;danger&#x22; | &#x22;neutral&#x22; | &#x22;success&#x22;">
  Shared semantic color that overrides the color of buttons in the group.
</ParamField>

<ParamField body="framed" type="boolean" default="false">
  Add a translucent frame with padding and concentric corners. Button sizes and appearance remain independent unless set on the group.
</ParamField>

<ParamField body="render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="size" type="&#x22;md&#x22; | &#x22;sm&#x22;">
  Shared button height that overrides the size of buttons in the group.
</ParamField>

<ParamField body="variant" type="&#x22;ghost&#x22; | &#x22;outline&#x22; | &#x22;soft&#x22; | &#x22;solid&#x22;">
  Shared surface treatment that overrides the variant of buttons in the group.
</ParamField>

## Detached controls

Set `attached={false}` to keep each control's rounded corners and a 2px gap. Shared size, surface, and color still apply through wrappers and tooltip anchors.

## Framed controls

Set `framed` to add a translucent background, border, 2px padding, and concentric corners. The frame works with attached or detached controls and preserves each button's size and appearance unless you set them on the group. Use `size="xs"` on [LightIconButton](/ui/components/input/light-icon-button) for compact 20px actions.

<StoryEmbed storyId="ui-input-button-buttongroup--framed-documentation" title="Framed button group" height={180} />

```tsx theme={null}
import { LightIconButton } from 'twenty-ui/components';
import { IconPlus, IconTrash } from 'twenty-ui/icon';
import { ButtonGroup } from 'twenty-ui/primitives/input';

export const CompactRecordActions = () => (
  <ButtonGroup framed attached={false} aria-label="Record actions">
    <LightIconButton size="xs" aria-label="Add" emphasis="subtle">
      <IconPlus />
    </LightIconButton>
    <LightIconButton size="xs" aria-label="Delete" emphasis="subtle" disabled>
      <IconTrash />
    </LightIconButton>
  </ButtonGroup>
);
```

## Updating existing groups

Replace `IconButtonGroup` and its `iconButtons` array with `ButtonGroup framed attached={false}` and explicit children. Replace `InsideButton` with `LightIconButton size="xs"`. Each button owns its accessible name, action handler, disabled state, and optional tooltip.
