Segmented Morph Toggle
A segmented control whose selected block flows and morphs to the new option on a spring.
A segmented control component: the selected block flows between options on a spring using a layoutId shared element, stretching slightly along the direction of travel and then springing back, so it glides into place like a liquid. It supports controlled and uncontrolled modes, three sizes, icons and disabled options, and comes with full keyboard operation built in.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add segmented-morph-toggle.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<SegmentedMorphToggle/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/segmented-morph-toggle.en.jsonOr, once registries are configured in components.json, install it as @webberui/segmented-morph-toggle.
Usage
import { SegmentedMorphToggle } from "@/components/ui/segmented-morph-toggle";
const [period, setPeriod] = React.useState("monthly");
<SegmentedMorphToggle
ariaLabel="Billing period"
value={period}
onChange={setPeriod}
options={[
{ value: "monthly", label: "Monthly" },
{ value: "quarterly", label: "Quarterly" },
{ value: "yearly", label: "Yearly" },
]}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
options | SegmentedMorphOption[] | — | The option list; each entry has a unique value and a label, with optional icon and disabled |
value | string | — | The current value in controlled mode; once provided, it is fully controlled from outside |
defaultValue | string | the first option | Initial value in uncontrolled mode |
onChange | (value: string) => void | — | Callback when the selected value changes |
size | "sm" | "md" | "lg" | "md" | Size (padding and font size) |
ariaLabel | string | — | Group label for assistive technology |
className | string | — | Forwarded to the outermost container |
Accessibility
- Uses
role="radiogroup"androle="radio", with the selected state marked byaria-checked - Roving tabindex: Tab only lands on the selected item,
←/→/↑/↓cycle within the group, andHome/Endjump to the first and last - Disabled options are marked
disabled, skipped automatically by keyboard navigation, and not clickable with the mouse either - When the user has "reduce motion" enabled at the system level, the block jumps straight to the new position without playing the liquid stretch animation
- Name the group with
ariaLabelso screen readers announce what the toggle is for