Tabs
A segmented control. The indicator's edges are pulled outward as it launches, and the container itself gives way where the indicator slams into it.
Usage
<Tabs
size="md"
spring="bouncy"
intensity="normal"
items={[
{ value: "A", label: "A" },
{ value: "B", label: "B" },
]}
/>How the motion works
The indicator is two independent edge springs rather than one box: its width is simply however far apart the left and right edges are on a given frame, so the deformation is real geometry and not a scale hack. Selecting a tab kicks both edges outward along the axis of travel — the trailing edge drags, the leading edge runs past its mark — so the body tugs open under the impulse and snaps closed as it settles. The container is a separate deformable skin whose walls only ever move through contact: leaving an end tab shoves the near wall immediately because the indicator is already resting on it, while arriving at an end tab parks its impulse until the leading edge has actually crossed the room, and a hop between middle tabs touches neither wall so neither moves. The walls are then floored at the indicator's penetration depth, so the container can never be smaller than the thing inside it; past a limit the wall holds and the body compresses against it instead.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| items | TabItem[] | — | Each has value, label and optional disabled. |
| value | string | — | Controlled selection. |
| defaultValue | string | — | Initial uncontrolled selection. |
| onChange | (value: string) => void | — | Fires on selection change. |
| pill | boolean | false | Fully rounded ends. |
| stretch | boolean | false | Fill the parent width. |
| intensity | "subtle" | "normal" | "strong" | "normal" | Scales the velocity stretch. |
