Button group
Keep related controls together, such as a main action and its menu or a field and its submit button.
<script setup lang="ts">import { Archive, ArrowLeft, Clock, Ellipsis, Flag, Pencil, Trash2 } from '@lucide/vue'import { UiButtonGroup, UiIconButton, UiButton, UiMenu, UiListItem, UiConfirm, UiToaster, useConfirm } from 'grani' const { confirm } = useConfirm() const remove = () => confirm({ title: 'Delete the message?', message: 'It is removed for everyone. This cannot be undone.', confirmLabel: 'Delete', tone: 'danger', })</script> <template> <UiButtonGroup ariaLabel="Message actions"> <UiButtonGroup ariaLabel="Back"> <UiIconButton :icon="ArrowLeft" ariaLabel="Back to the inbox" /> </UiButtonGroup> <UiButtonGroup ariaLabel="Triage"> <UiButton variant="outline"> <Archive aria-hidden="true" /> Archive </UiButton> <UiButton variant="outline"> <Flag aria-hidden="true" /> Report </UiButton> </UiButtonGroup> <UiButtonGroup ariaLabel="Snooze"> <UiButton variant="outline"> <Clock aria-hidden="true" /> Snooze </UiButton> <UiMenu align="end"> <template #trigger> <UiIconButton :icon="Ellipsis" ariaLabel="More actions" /> </template> <UiListItem as="button" title="Edit"> <template #media><Pencil /></template> </UiListItem> <UiListItem as="button" title="Delete" tone="danger" @click="remove"> <template #media><Trash2 /></template> </UiListItem> </UiMenu> </UiButtonGroup> </UiButtonGroup> <!-- Once, at the app's root: leave out what the app has there already. --> <UiConfirm /> <UiToaster /></template>
Also called segmented buttons, joined buttons, split button.
Usage
<UiButtonGroup>…</UiButtonGroup> With GraniResolver in the Vite config, a template needs no import: set it up once.
API
| Name · type | Default | Description |
|---|---|---|
| ariaLabelstring | Name of the group for a screen reader: "Pagination", "Period". Inside UiField group the legend names it. | |
| orientationhorizontal | vertical= "horizontal" | "horizontal" | Controls in a row or in a column. |
Anything else lands on the root element: native attributes, aria-*, data-testid.
When to use another component
| When you need | Take |
|---|---|
| One choice among a few | Radio group segmented |
| A lone action | Button |
| The search and the filters over a list | Table toolbar |