Segmented Radio Group
Exclusive form or filter value styled as a segmented control.
Use SegmentedRadioGroup when one value must always stay selected and the choice does not change the URL — billing period, a view mode, a status filter, a field type. It is a Radio Group with the shared segmented-control styles. Do not use Tabs here: there are no associated panels. For destination links, use Segmented Nav. See Segmented controls for the full pick list.
import { SegmentedRadio, SegmentedRadioGroup } from "@coss/ui/shared/segmented-radio-group";Example
Billing period on plans and the upgrade dialog. Copy is paraphrased.
apps/web · billing period
MonthlyAnnual25% off
<SegmentedRadioGroup value={billingPeriod} onValueChange={onBillingPeriodChange}>
<SegmentedRadio className="grow" value="monthly">
{t("monthly")}
</SegmentedRadio>
<SegmentedRadio className="grow" value="annual">
{t("upgrade_billing_annual")}
<Badge className="not-in-data-checked:opacity-72" variant="info" size="sm">
{t("discount_25")}
</Badge>
</SegmentedRadio>
</SegmentedRadioGroup>Bookings list / calendar is icon-only. Height still comes from size="sm"; aspect-square px-0 makes the hit target square.
apps/web · bookings view
<SegmentedRadioGroup size="sm" value={view} onValueChange={setView}>
<SegmentedRadio className="aspect-square px-0" value="list" aria-label={t("list_view")} title={t("list_view")}>
<MenuIcon aria-hidden="true" />
</SegmentedRadio>
<SegmentedRadio className="aspect-square px-0" value="calendar" aria-label={t("calendar_view")} title={t("calendar_view")}>
<CalendarIcon aria-hidden="true" />
</SegmentedRadio>
</SegmentedRadioGroup>API
| Prop / part | Type | Notes |
|---|---|---|
SegmentedRadioGroup | RadioGroupPrimitive.Props | Coss Radio Group root plus segmented surface. |
SegmentedRadio | RadioPrimitive.Root.Props | One option. Always-on exclusive selection. |
size | "default" | "lg" | "sm" | Shared with Tabs and Segmented Nav. Defaults to "default". Set on the group; override per item only when needed. |
value / onValueChange | Radio Group controlled API | Ignore null unless the product can clear the selection (none of the current call sites do). |
className on an item | string | Escape hatches used in product: grow, aspect-square px-0. |
Call sites
| File | Notes |
|---|---|
apps/web/modules/billing/components/BillingPeriodToggle.tsx | Monthly / annual, grow |
apps/web/modules/bookings/components/ViewToggleButton.tsx | List / calendar icons, size="sm" |
apps/web/modules/settings/admin/oauth/components/status-filter.tsx | Pending / approved / rejected |
apps/web/modules/settings/admin/events-admin-view.tsx | Admin events filter |
apps/web/modules/settings/admin/discover-admin-view.tsx | Admin Discover filter |
apps/web/modules/insights/components/routing/WrongAssignmentReportsDashboard.tsx | Pending / handled, size="sm" |
apps/web/modules/apps/routing-forms/ai/routing-form-ai-view.tsx | Routing form AI view mode |
packages/features/eventtypes/components/tabs/advanced/FormBuilder.tsx | Email / phone booking question, size="sm" |
apps/web/modules/ee/organizations/components/CreateANewOrganizationForm.tsx | Billing mode and period (admin) |
apps/web/modules/events/components/tabs/location-tab.tsx | In-person / virtual |
Example URLs
Not exhaustive — a few places you can open locally (e.g. http://localhost:3000) to see this in product.
| Path | Notes |
|---|---|
/settings/billing/plans | Monthly / annual |
/bookings/upcoming | List / calendar (desktop) |
/settings/admin/oauth | Status filter (admin) |
/insights/wrong-routing | Pending / handled |
/event-types/<id>?tabName=advanced | Email / phone — opens in Form Builder |
/settings/organizations/new | Billing mode / period (admin, billing enabled) |
/events/<id>?tabName=location | In-person / virtual |
Source
On This Page