Skip to Content
Columbus

Segmented Control

A set of mutually exclusive options shown as a row of segments.

MonthlyYearly

Installation

pnpm dlx shadcn@latest add @columbus/segmented-control

Usage

Segmented Control provides the look: the surface, the items, and an indicator that slides to the active item. The behavior comes from the element you pass to render, like a radio group, a toggle group, or a <nav>.

import {
  RadioGroupPrimitive,
  RadioPrimitive,
} from "@/components/ui/radio-group";
import {
  SegmentedControl,
  SegmentedControlItem,
} from "@/components/ui/segmented-control";

<SegmentedControl
  aria-label="Billing period"
  render={<RadioGroupPrimitive defaultValue="monthly" />}
>
  <SegmentedControlItem render={<RadioPrimitive.Root value="monthly" />}>
    Monthly
  </SegmentedControlItem>
  <SegmentedControlItem render={<RadioPrimitive.Root value="yearly" />}>
    Yearly
  </SegmentedControlItem>
</SegmentedControl>;

Put defaultValue, value, onValueChange, or href on the element you pass to render. Use the radio group primitives, not RadioGroup and Radio, so no radio circle is drawn.

An item is active when it has data-checked (radio), aria-current="page" (link), or data-pressed (toggle). When no item is active, the indicator hides.

Render a <nav> and links. Set aria-current="page" on the current link.

Toggle group

Use a toggle group for a single filter that can be cleared.

Sizes

MonthlyYearly
MonthlyYearly
MonthlyYearly

Segmented Control or Tabs?

Use Tabs when each option shows its own panel. Tabs use the same sizes and indicator, so both look the same.

API reference

Both parts accept a render prop and the attributes of the element they render.

SegmentedControl

Renders a <div> by default.

Prop

Type

SegmentedControlItem

Renders a <button type="button"> by default.

Prop

Type

On this page