<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
| Prop | Type | Default | Description |
|---|---|---|---|
default slot | slot | - | 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. |
class | string | - | Forwarded to the root element. |
aria-label | string | - | Name for the group. Required in practice. |