Segmented Control
May 2023
A segmented control is a linear set of two or more segments, each of which functions as a button. Segmented controls are used to switch between different options or views, they are great alternatives to Tabs and Radio Groups.
My implementation is based on RadixUI and doesn't use external libraries like Motion.
Installation
You can install and use this component with a single command. It's powered by Shadcn CLI.
npx shadcn@latest add "https://gaievskyi.com/r/segmented-control"
Implementation
This segmented control implementation uses Radix UI Tabs primitive and a useTabObserver hook for smooth animations. Here's how to build it step by step.
npm install @radix-ui/react-tabs @radix-ui/react-slot
Add cn() helper
Used to manipulate classNames in a handy way. I'm not a fan of rewriting classes in runtime, but we don't have a better way to do it in React yet.
Add mergeRefs() utility
Used to merge multiple refs into a single one. I'd love to have it in React natively, follow the React discussion. Anyways, we need it for useTabObserver hook, since it returns a listRef
that should be merged with the component ref.
Tab Observer Hook
The magic happens with a custom hook that observes tab changes and provides smooth animation:
Floating Background
Animated background that slides behind active element. I use Tailwind motion-safe:
utility to disable the animation for a11y reasons. It's not even a best practice, but a must-have feature for people who are sick or just prefer not to see animations on their devices.
Segmented Control
The root component is a simple Radix TabsPrimitive.
Segmented Control List
The list component that wraps the segmented control triggers.
Segmented Control Trigger
The trigger component for switching the control.
Exports
Don't forget to export the components:
Usage
Start with a simple two-option segmented control:
Controlled & Uncontrolled
You can use the segmented control in both controlled and uncontrolled modes: