GitHub
Core
Glass
Brutal
Humanist

Segmented Control

Segmented control allows users to select one option from a set of related choices. It features a sliding indicator animation, supports icons, two color variants (primary and neutral), and two visual styles (simple and expressive).

Segmented Control Playground

Segmented Control Playground
Preview
Code
List
Grid
Table
Compact
Controls
Type:
Primary
Neutral
Style:
Simple
Expressive
Size:
Small
Medium
Large
Display:
Icon + Text
Icon Only
Text Only
Width:
Equal
Content
Dividers:
Off
On

Installation

You can add the segmented control component to your project manually:

1

Install the following dependencies:

npm install @react-aria/focus
2

Copy and paste the following code into your project.

Loading source code...
3

Update the import paths to match your project setup.

Update the import aliases (e.g. @/components, @/utils) in the copied files to match your project's path configuration.

Basic Usage

import { useState } from 'react';
import { SegmentedControl } from '@versaui/ui/components/SegmentedControl';
import { List, GridFour, SquaresFour } from '@phosphor-icons/react';

const [view, setView] = useState('list');

// Basic segmented control (Simple style)
<SegmentedControl
  items={[
    { id: 'day', label: 'Day' },
    { id: 'week', label: 'Week' },
    { id: 'month', label: 'Month' },
  ]}
  selectedId={view}
  onChange={setView}
/>

// Expressive style
<SegmentedControl
  type="primary"
  style="expressive"
  items={[
    { id: 'day', label: 'Day' },
    { id: 'week', label: 'Week' },
    { id: 'month', label: 'Month' },
  ]}
  selectedId={view}
  onChange={setView}
/>

// Neutral variant with expressive style
<SegmentedControl
  type="neutral"
  style="expressive"
  items={[
    { id: 'day', label: 'Day' },
    { id: 'week', label: 'Week' },
    { id: 'month', label: 'Month' },
  ]}
  selectedId={view}
  onChange={setView}
/>

// With icons
<SegmentedControl
  items={[
    { id: 'list', label: 'List', icon: <List /> },
    { id: 'grid', label: 'Grid', icon: <GridFour /> },
    { id: 'board', label: 'Board', icon: <SquaresFour /> },
  ]}
  selectedId={view}
  onChange={setView}
/>

// Icon only mode
<SegmentedControl
  iconOnly
  items={[
    { id: 'list', icon: <List /> },
    { id: 'grid', icon: <GridFour /> },
    { id: 'board', icon: <SquaresFour /> },
  ]}
  selectedId={view}
  onChange={setView}
/>

// With dividers
<SegmentedControl
  showDividers
  items={[
    { id: 'all', label: 'All' },
    { id: 'active', label: 'Active' },
    { id: 'archived', label: 'Archived' },
  ]}
  selectedId={status}
  onChange={setStatus}
/>

// Content width mode
<SegmentedControl
  widthMode="content"
  items={[
    { id: 'all', label: 'All' },
    { id: 'active', label: 'Active' },
    { id: 'archived', label: 'Archived' },
  ]}
  selectedId={status}
  onChange={setStatus}
/>

// Neutral type
<SegmentedControl
  type="neutral"
  items={[
    { id: 'all', label: 'All' },
    { id: 'active', label: 'Active' },
    { id: 'archived', label: 'Archived' },
  ]}
  selectedId={status}
  onChange={setStatus}
/>

SegmentItem Interface

interface SegmentItem {
  id: string;        // Unique identifier
  label?: string;    // Button text
  icon?: ReactNode;  // Optional icon
}

Accessibility

  • Each segment uses role="button" with aria-pressed to indicate selection
  • Keyboard activation with Enter and Space keys
  • aria-disabled indicates disabled state
  • Focus ring visible on keyboard navigation

SegmentedControl Props

PropTypeDefaultDescription
itemsSegmentItem[]—Array of segment items.
selectedIdstring—Currently selected segment ID.
onChange(id: string) => void—Selection change handler.
type'primary' | 'neutral''primary'Color theme variant.
style'simple' | 'expressive''simple'Visual style treatment. Simple uses clean solid surfaces; expressive uses rich gradient fills, outlines, and inset shadows.
size'small' | 'medium' | 'large''medium'Button size.
iconOnlybooleanfalseShow only icons (no labels).
showDividersbooleanfalseShow vertical dividers between segments.
widthMode'equal' | 'content''equal'Equal distributes segments evenly across available width. Content sizes segments to fit their content.

On this page