Skip to content
gnosticaignostic-ui
Esc
↑↓navigate↵open⌘Jpreview
On this page

Segmented Control

Shared Astro style recipes for related radio choices, navigation links, and pressed buttons.

---
import { RadioGroup } from "@/components/ui/radio-group"
import { Toggle } from "@/components/ui/toggle"
import {
  segmentedControlRootClassName,
  segmentedControlItemVariants,
} from "@gnosticai/ui/lib/segmented-control"
---

<div class="grid gap-6">
  {(["sm", "default", "lg"] as const).map((size) => (
    <RadioGroup
      name={`billing-${size}`}
      defaultValue="monthly"
      aria-label={`Billing period, ${size}`}
      class={`${segmentedControlRootClassName} flex-row`}
    >
      <button
        type="button"
        data-slot="radio-group-item"
        data-value="monthly"
        class={segmentedControlItemVariants({ size, state: "checked" })}
      >
        Monthly
      </button>
      <button
        type="button"
        data-slot="radio-group-item"
        data-value="yearly"
        class={segmentedControlItemVariants({ size, state: "checked" })}
      >
        Yearly
      </button>
    </RadioGroup>
  ))}
  <nav aria-label="Project guides" class={segmentedControlRootClassName}>
    <a
      class={segmentedControlItemVariants({ state: "current" })}
      href="/components/segmented-control"
      aria-current="page"
    >
      Choices
    </a>
    <a
      class={segmentedControlItemVariants({ state: "current" })}
      href="/components/tabs"
    >
      Panels
    </a>
    <a
      class={segmentedControlItemVariants({ state: "current" })}
      href="/components/group"
    >
      Actions
    </a>
  </nav>
  <div
    role="group"
    aria-label="Independent view options"
    class={segmentedControlRootClassName}
  >
    <Toggle
      defaultPressed
      class={segmentedControlItemVariants({ state: "pressed" })}
    >
      Guides
    </Toggle>
    <Toggle class={segmentedControlItemVariants({ state: "pressed" })}>
      Grid
    </Toggle>
  </div>
</div>
Open preview in a new tab

Installation

bunx --bun shadcn@latest add @gnosticai/segmented-control

The recipe supplies classes. Add the control used by your composition:

bunx --bun shadcn@latest add @gnosticai/radio-group @gnosticai/toggle

Usage

import {
	segmentedControlRootClassName,
	segmentedControlItemVariants,
	segmentedControlItemLayoutClassName,
} from "@/lib/segmented-control"

Apply the root class to a group or navigation element. Apply the item recipe to each child. The radio example uses the existing RadioGroup controller with button elements marked data-slot="radio-group-item" and stable data-value attributes. Its flex-row class changes the group’s usual column layout.

API reference

size accepts sm, default, or lg. state accepts checked, current, or pressed. These recipes read data-checked, aria-current="page", and aria-pressed="true", respectively. Read the source for all exported classes and types.

Choose the underlying control

Use Radio Group for one form value. Use links for destinations, with aria-current="page" on the current route. Use Toggle for independent options. Adjacent toggles do not become an exclusive Toggle Group. Use Tabs when a choice shows a matching content panel; Tabs keeps its own indicator and panel relationships.

Keyboard and form behavior

The recipe has no client script. Radio Group keeps its arrow-key selection and named form value. Links keep browser navigation and open-in-new-tab behavior. Toggle keeps its pressed state and Space activation. Give each group a name that explains the shared choice and test disabled items in the final page.

Theme and layout

The outer muted surface and selected item use shared theme tokens. Keep the labels short and choose one size for the group. A long row can need a different layout on a phone; a segmented appearance does not provide overflow controls. Use Group for joined action buttons with visible borders.

Was this page helpful?