A billing period switch for pricing sections: a thumb slides between Monthly and Yearly (or any periods you pass) on a soft spring, measured from each label so any length fits, and a savings badge like "2 months free" turns green and pops when its period is picked. It renders whatever you pass as children with the picked period, so a price-tag underneath follows it and its digits roll. Built from native radios, so arrow keys, forms and screen readers work as they do in any radio group. Three tones and three sizes.
The import and the props worth knowing about, in one place.
import { PriceToggle } from "@/components/beste/component/price-toggle";
import { PriceTag } from "@/components/beste/component/price-tag";
// The price follows the switch and its digits roll
<PriceToggle defaultValue="monthly">
{(period) =>
period === "yearly" ? (
<PriceTag amount={120} period="/yr" periodLabel="per year" />
) : (
<PriceTag amount={12} period="/mo" periodLabel="per month" />
)
}
</PriceToggle>
// Your own periods, controlled
<PriceToggle
value={period}
onValueChange={setPeriod}
options={[
{ value: "month", label: "Month" },
{ value: "quarter", label: "Quarter", badge: "Save 10%" },
{ value: "year", label: "Year", badge: "Save 20%" },
]}
tone="outline" // "muted" (default) | "outline" | "ghost"
size="sm" // "sm" | "default" | "lg"
/>Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.
| Tab | Reach the group; focus lands on the picked period. |
|---|---|
| Arrow keys | Move to the other period and pick it, as in any radio group. |
Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
options | PriceToggleOption[] | — | The periods to choose from. Defaults to Monthly and Yearly. |
value | string | — | The picked period, controlled. |
defaultValue | string | — | The picked period, uncontrolled. Defaults to the first option. |
onValueChange | (value: string) => void | — | |
children | (value: string) => React.ReactNode | — | Rendered under the switch with the picked period, e.g. a PriceTag whose amount follows it. |
aria-label | string | — | Accessible name for the group. |
name | string | — | Form name for the underlying radios. |
disabled | boolean | — | |
tone | "muted" | "outline" | "ghost" | — | |
size | "sm" | "default" | "lg" | — | |
className | string | — |