Inputs
ButtonGroup Attach related buttons into one control, horizontal or vertical, with a shared outer radius and a single-line seam.
< script >
import { Button, ButtonGroup } from "@codeatlasdev/ui" ;
</ script >
< ButtonGroup aria-label = "View range" >
< Button variant = "outlined" tone = "neutral" >Day</ Button >
< Button variant = "outlined" tone = "neutral" >Week</ Button >
</ ButtonGroup >
ButtonGroup is role="group": give it an aria-label (or aria-labelledby) so a screen reader announces what the buttons share; a dev warning fires without one. It only changes how the buttons sit: each keeps its own variant, size, onclick, loading and disabled state, and its own Tab stop (Tab moves through the group, there is no roving focus). The inner corners are square, the outer ones keep --ca-radius-control, and neighbours overlap by one border so the seam is a single line. The hovered, open or keyboard-focused button is raised so its ring is never half hidden.
Members are Button, IconButton and a DropdownMenu whose triggerChild is one of them (the menu itself is portaled, only the trigger sits in the group): that is the split button. orientation="vertical" stacks them.
It is for actions. A single choice that stays selected is SegmentedControl ; a set of toggles is ToggleGroup .
#980 Text, icon and filled groups Day Week Month
Approve Reject
Reference #980 · Pick in the gallery
Code <script lang="ts">
import { Button, ButtonGroup, IconButton } from '@codeatlasdev/ui';
import { Bold, Italic, Underline } from '@lucide/svelte';
</script>
<div class="col">
<ButtonGroup aria-label="View range">
<Button variant="outlined" tone="neutral">Day</Button>
<Button variant="outlined" tone="neutral">Week</Button>
<Button variant="outlined" tone="neutral">Month</Button>
</ButtonGroup>
<ButtonGroup aria-label="Text style">
<IconButton variant="outlined" tone="neutral" aria-label="Bold"><Bold size={16} /></IconButton>
<IconButton variant="outlined" tone="neutral" aria-label="Italic"><Italic size={16} /></IconButton>
<IconButton variant="outlined" tone="neutral" aria-label="Underline"><Underline size={16} /></IconButton>
</ButtonGroup>
<ButtonGroup aria-label="Review">
<Button variant="filled">Approve</Button>
<Button variant="destructive">Reject</Button>
</ButtonGroup>
</div>
<style>
.col { display: grid; gap: var(--ca-space-3); justify-items: start; }
</style>
#981 A DropdownMenu trigger as the last member, and `orientation='vertical'`.
Reference #981 · Pick in the gallery
Code <script lang="ts">
import {
Button,
ButtonGroup,
DropdownMenu,
DropdownMenuItem,
IconButton,
} from '@codeatlasdev/ui';
import { ChevronDown, ChevronLeft, ChevronRight } from '@lucide/svelte';
</script>
<div class="row">
<ButtonGroup aria-label="Publish">
<Button variant="filled">Publish</Button>
<DropdownMenu align="end">
{#snippet triggerChild(props)}
<IconButton variant="filled" aria-label="More publish options" {...props}><ChevronDown size={16} /></IconButton>
{/snippet}
<DropdownMenuItem>Schedule</DropdownMenuItem>
<DropdownMenuItem>Save as draft</DropdownMenuItem>
</DropdownMenu>
</ButtonGroup>
<ButtonGroup aria-label="Pages" orientation="vertical">
<IconButton variant="outlined" tone="neutral" aria-label="Previous page"><ChevronLeft size={16} /></IconButton>
<IconButton variant="outlined" tone="neutral" aria-label="Next page"><ChevronRight size={16} /></IconButton>
</ButtonGroup>
</div>
<style>
.row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--ca-space-6); }
</style>
Props Prop Type Default Description orientation'horizontal' | 'vertical''horizontal'Direction the buttons are attached in. Exposed as `data-orientation`. aria-labelstringundefinedNames the group. Required unless `aria-labelledby` is set. childrenSnippet– `Button`, `IconButton` or a `DropdownMenu` with a `triggerChild`. classstring''Extra class names.