Phi
ButtonGroup
@dicehub/phiv1.0.0-beta.1

ButtonGroup

Joins a small set of tightly coupled buttons into one control, most commonly a split button.

<script setup>
import { Button } from "@dicehub/phi/components/button";
import { ButtonGroup } from "@dicehub/phi/components/button-group";
import { PhCaretDown } from "@phosphor-icons/vue";
</script>

<template>
  <ButtonGroup aria-label="Deploy">
    <Button variant="primary">Deploy</Button>
    <Button :icon="PhCaretDown" aria-label="More deploy options" shape="square" variant="primary" />
  </ButtonGroup>
</template>

Installation

Barrel

import { ButtonGroup } from "@dicehub/phi";

Granular

import { ButtonGroup } from "@dicehub/phi/components/button-group";

Usage

<script setup>
import { Button } from "@dicehub/phi/components/button";
import { ButtonGroup } from "@dicehub/phi/components/button-group";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@dicehub/phi/components/dropdown";
import { PhCaretDown } from "@phosphor-icons/vue";
</script>

<template>
  <ButtonGroup aria-label="Deploy">
    <Button variant="primary">Deploy</Button>
    <DropdownMenu>
      <DropdownMenuTrigger>
        <Button :icon="PhCaretDown" aria-label="More deploy options" shape="square" variant="primary" />
      </DropdownMenuTrigger>
      <DropdownMenuContent>
        <DropdownMenuItem value="staging">Deploy to staging</DropdownMenuItem>
        <DropdownMenuItem value="production">Deploy to production</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  </ButtonGroup>
</template>

Children keep their own variant, size, and shape. The group only handles layout: it flattens the joining corners and overlaps the controls by one pixel so they share a single seam. Pass anaria-label so assistive technology can name the set.

For multiple independent controls — a formatting bar or a page-level set of actions — useToolbar instead. Toolbar provides the roaming-focus keyboard model that a button group must not add.

Examples

Split Button

<script setup>
import { Button } from "@dicehub/phi/components/button";
import { ButtonGroup } from "@dicehub/phi/components/button-group";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@dicehub/phi/components/dropdown";
import { PhCaretDown } from "@phosphor-icons/vue";
</script>

<template>
  <ButtonGroup aria-label="Deploy">
    <Button variant="primary">Deploy</Button>
    <DropdownMenu>
      <DropdownMenuTrigger>
        <Button :icon="PhCaretDown" aria-label="More deploy options" shape="square" variant="primary" />
      </DropdownMenuTrigger>
      <DropdownMenuContent>
        <DropdownMenuItem value="staging">Deploy to staging</DropdownMenuItem>
        <DropdownMenuItem value="production">Deploy to production</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  </ButtonGroup>
</template>

Mixed Controls

Buttons, links, and dropdown triggers keep their own variant, size, and shape. ButtonGroup only joins their corners.

<script setup>
import { Button, LinkButton } from "@dicehub/phi/components/button";
import { ButtonGroup } from "@dicehub/phi/components/button-group";
</script>

<template>
  <ButtonGroup aria-label="Documentation actions">
    <Button variant="secondary">Open editor</Button>
    <LinkButton href="/docs/cli" variant="secondary">Read the CLI guide</LinkButton>
  </ButtonGroup>
</template>

Disabled Control with Tooltip

A disabled Button with a title renders a tooltip trigger wrapper. The group keeps its seam and rounded outer corners.

<script setup>
import { Button } from "@dicehub/phi/components/button";
import { ButtonGroup } from "@dicehub/phi/components/button-group";
</script>

<template>
  <ButtonGroup aria-label="Publish">
    <Button>Save draft</Button>
    <Button disabled title="Requires the reviewer role">Publish</Button>
  </ButtonGroup>
</template>

Sizes

Set the same size on every control so the joined seam stays straight.

<script setup>
import { Button } from "@dicehub/phi/components/button";
import { ButtonGroup } from "@dicehub/phi/components/button-group";
</script>

<template>
  <ButtonGroup aria-label="Small actions">
    <Button size="sm">Cancel</Button>
    <Button size="sm" variant="primary">Confirm</Button>
  </ButtonGroup>
</template>

Right to Left

Corners and the one-pixel overlap use logical properties, so the group mirrors under dir="rtl".

<script setup>
import { Button } from "@dicehub/phi/components/button";
import { ButtonGroup } from "@dicehub/phi/components/button-group";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@dicehub/phi/components/dropdown";
import { PhCaretDown } from "@phosphor-icons/vue";
</script>

<template>
  <ButtonGroup aria-label="إجراءات" dir="rtl">
    <Button>إلغاء</Button>
    <DropdownMenu dir="rtl">
      <DropdownMenuTrigger>
        <Button :icon="PhCaretDown" aria-label="المزيد من الخيارات" shape="square" />
      </DropdownMenuTrigger>
      <DropdownMenuContent>
        <DropdownMenuItem value="save">حفظ</DropdownMenuItem>
        <DropdownMenuItem value="discard">تجاهل</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  </ButtonGroup>
</template>

API Reference

PropTypeDefaultDescription
default slotslot-The tightly coupled controls to join. Typically two or three Button, LinkButton, or dropdown trigger elements.
role"group""group"Fixed. Assistive technology announces the joined controls as a related set, so pass an aria-label.
classstring-Forwarded to the root element.
aria-labelstring-Name for the group. Required in practice.