Skip to content
Aggarly OS
  • Getting Started
    • Introduction
  • Foundations
    • Colors
    • Spacing
    • Radius
    • Typography
    • Shadows
    • Z-Index
    • Gradients
    • Tokens
    • RTL & Direction
    • Theming
  • Layout
    • Containers
    • Grid System
    • Layout Utilities
  • Components
    • Alerts
    • Avatars
    • Buttons
    • Button Group
    • Badges
    • Inputs
    • Select
    • Checkbox
    • Counters-timers
    • Radio
    • Switch
    • Stepper
    • Select-pro
    • Cards
    • Modals
    • Dropdown
    • Popover
    • Tooltip
    • Accordion
    • Breadcrumb
    • Tabs
    • Navbar
    • List Group
    • Toasts
    • Skeleton
    • Pagination
    • Progress
    • Table
    • Icons
    • Form
    • Ribbons
    • Spinner
    • Offcanvas
    • Feedback
    • Grid
    • Data UI
  • Data UI
    • Overview
  • Platform
    • Reference DataCore
  • Widgets
    • KPI
    • Analytics
    • Behavior
  • Brand
    • Logo
    • Brand Usage
Components/Button Group

Button Group

ButtonGroup composes Button elements into premium groups: connected segmented actions, or a true segmented-control experience with an animated pill indicator. Supports single-select toggle behavior, RTL-aware keyboard navigation, vertical orientation, and a toolbar-grade elevated surface.

Segmented buttons

Connected segments are ideal for related actions (Back / Next / Save) and split actions.

Show code
Segmented groups (JSX)
import { ButtonGroup } from "@/design-system/components/ButtonGroup";
import { Button } from "@/design-system/components/Button";

export function Example() {
  return (
    <ButtonGroup segmented variant="primary" size="sm" aria-label="Wizard actions">
      <Button>Back</Button>
      <Button>Next</Button>
      <Button>Save</Button>
    </ButtonGroup>
  );
}

import { ChevronDown } from "lucide-react";

<ButtonGroup segmented variant="primary" size="sm" aria-label="Split action">
  <Button>New note</Button>
  <Button iconOnly aria-label="More options">
    <ChevronDown size={16} />
  </Button>
</ButtonGroup>

Premium segmented control

Innovative enterprise style: a true segmented-control surface with a moving pill indicator for high scanability.

Show code
Control segmented (JSX)
import { useState } from "react";
import { ButtonGroup } from "@/design-system/components/ButtonGroup";
import { Button } from "@/design-system/components/Button";

export function Example() {
  const [view, setView] = useState<"grid" | "list">("grid");

  return (
    <ButtonGroup
      toggle
      segmented
      segmentedStyle="control"
      indicator
      tone="primary"
      size="sm"
      value={view}
      onChange={(v) => setView(v as any)}
      aria-label="View mode"
    >
      <Button itemValue="grid" leadingIcon={<LayoutGrid size={16} />}>Grid</Button>
      <Button itemValue="list" leadingIcon={<List size={16} />}>List</Button>
    </ButtonGroup>
  );
}

Toggle group (icon-only)

Single-select toggle controls with correct aria-pressed semantics and roving tabIndex. Perfect for editors and toolbars.

Show code
Icon-only toggle (JSX)
const [alignment, setAlignment] = useState<"left" | "center" | "right">("center");

<ButtonGroup
  toggle
  segmented
  segmentedStyle="control"
  tone="neutral"
  size="sm"
  value={alignment}
  onChange={(v) => setAlignment(v as any)}
  aria-label="Text alignment"
>
  <Button itemValue="left" iconOnly aria-label="Align left"><AlignLeft size={16} /></Button>
  <Button itemValue="center" iconOnly aria-label="Align center"><AlignCenter size={16} /></Button>
  <Button itemValue="right" iconOnly aria-label="Align right"><AlignRight size={16} /></Button>
</ButtonGroup>

Vertical segmented control

Vertical orientation is useful for tight side panels and settings stacks.

Show code
Vertical control segmented (JSX)
const [mode, setMode] = useState<"summary" | "notes" | "docs">("summary");

<ButtonGroup
  toggle
  segmented
  segmentedStyle="control"
  orientation="vertical"
  tone="primary"
  size="sm"
  value={mode}
  onChange={(v) => setMode(v as any)}
  aria-label="Student panel"
>
  <Button itemValue="summary">Summary</Button>
  <Button itemValue="notes">Notes</Button>
  <Button itemValue="docs">Documents</Button>
</ButtonGroup>

Elevated toolbar group

Add an elevated surface for dense app toolbars to improve separation on busy screens.

Show code
Elevated toolbar segmented (JSX)
const [range, setRange] = useState<"day" | "week" | "month">("week");

<ButtonGroup
  toggle
  segmented
  segmentedStyle="control"
  elevated
  tone="primary"
  size="sm"
  value={range}
  onChange={(v) => setRange(v as any)}
  aria-label="Time range"
>
  <Button itemValue="day">Day</Button>
  <Button itemValue="week">Week</Button>
  <Button itemValue="month">Month</Button>
</ButtonGroup>

Scrollable segmented control

Enterprise overflow pattern for wide segmented controls without breaking layouts.

Show code
Scrollable segmented (JSX)
const [tab, setTab] = useState("t-1");

<ButtonGroup
  toggle
  segmented
  segmentedStyle="control"
  scrollable
  tone="neutral"
  size="sm"
  value={tab}
  onChange={(v) => setTab(v)}
  aria-label="Overflow segmented control"
>
  <Button itemValue="t-1">Overview</Button>
  <Button itemValue="t-2">Notes</Button>
  <Button itemValue="t-3">Documents</Button>
  <Button itemValue="t-4">Billing</Button>
  <Button itemValue="t-5">Sessions</Button>
  <Button itemValue="t-6">Exports</Button>
  <Button itemValue="t-7">Audit</Button>
</ButtonGroup>

Non-segmented grouping

When segmented is false, the group behaves like a clean inline cluster with spacing.

Show code
Non-segmented group (JSX)
import { ButtonGroup } from "@/design-system/components/ButtonGroup";
import { Button } from "@/design-system/components/Button";

export function Example() {
  return (
    <ButtonGroup segmented={false} aria-label="Inline actions">
      <Button variant="primary">Create</Button>
      <Button variant="outline">Export</Button>
      <Button variant="ghost">Cancel</Button>
    </ButtonGroup>
  );
}