All pages

Components

Segmented Filter

The filter the shelf screens share: a row of segments on one plate, exactly one of them in force. A segmented control rather than a strip of words, because the plate is what says which alternative you are in — a bare strip leaves that to a colour change alone.

Usage

Radix's single-select toggle group underneath, which gives roving focus and radio semantics for free. label is the accessible name — what it is these segments filter.

import { SegmentedFilter } from "@/components/base/segmented-filter";

<SegmentedFilter
label="Lists"
value={value}
onChange={setValue}
segments={[
  { value: "all", label: "All", count: 12 },
  { value: "published", label: "Published", count: 9 },
  { value: "drafts", label: "Drafts", count: 3 },
  { value: "archived", label: "Archived", count: null },
]}
/>

Counts

The count is what makes the control worth reading before you click it — “3 drafts” answers the question that brought you here. Pass null while a number is not known yet: the segment keeps its place and simply carries no count until it is.

Behaviour

Radix's one unwanted behaviour is deselection — clicking the active segment clears the value — so an empty change is ignored, and callers pass an explicit “All” segment rather than modelling it as the absence of one. The row scrolls rather than wraps: twelve categories on a phone would otherwise stack three rows deep and push the shelf itself off the screen.