react-segmented-choice

Build segmented controls that feel like real UI

react-segmented-choice starts with a real radio group and gives you the hooks to shape it into custom switches, option selectors, toolbars and tab-like controls without giving up form behavior.

Primary Scale

A rating-style rail where selection moves along compact, evenly spaced targets.

1 / 16 - Scale

Start simple, then shape the control

Real control behavior

Native radio inputs, labels, keyboard movement and form-friendly state keep the control grounded in normal UI semantics.

CSS-first shaping

Use stable classes, public variables and geometry props to turn one component into switches, rails, toolbar controls and option selectors.

Interaction beyond tabs

Drag-to-select, animated indicators, overlay handles and cloned active content cover the cases where tabs start to feel too rigid.

Render the control, then shape it with CSS

Start with the accessible default, then tune the surface, option pills, active state and focus color from normal CSS.

Install
pnpm add react-segmented-choice
# or
npm install react-segmented-choice
# or
yarn add react-segmented-choice
Quick usage
import { SegmentedChoice } from 'react-segmented-choice';
import 'react-segmented-choice/styles.css';

export function ReportRange() {
  return (
    <SegmentedChoice
      ariaLabel="Report range"
      className="report-range"
      defaultValue="segmented"
      optionSizing="equal"
      options={[
        { value: 'react', label: 'React' },
        { value: 'segmented', label: 'Segmented' },
        { value: 'choice', label: 'Choice' },
      ]}
    />
  );
}
CSS styling
.report-range {
  --rsc-surface: #f8fafc;
  --rsc-border-color: #e5e7eb;
  --rsc-border-radius: 999px;
  --rsc-option-radius: 999px;
  --rsc-option-padding-inline: 14px;
  --rsc-text-color: #4b5563;
  --rsc-active-text-color: #ffffff;
  --rsc-indicator-color: #7c3aed;
  --rsc-focus-ring-color: rgba(124, 58, 237, 0.26);
}

.report-range.rsc-root .rsc-option-content {
  transition: color 200ms ease;
}

.report-range.rsc-root[data-dragging="true"]
  .rsc-option[data-selected="true"]:not([data-previewed="true"])
  .rsc-option-content {
  color: var(--rsc-text-color);
}

.report-range.rsc-root[data-dragging="true"]
  .rsc-option[data-previewed="true"]
  .rsc-option-content {
  color: var(--rsc-active-text-color);
}

Use the docs for API details and Storybook when you want to see the recipes in motion.

react-custom-switcher is the legacy predecessor. react-segmented-choice carries those original ideas forward as a cleaner, more flexible segmented control for current React projects.