Label Selector
Open in
Basic Example - Clothing Sizes
Select size
Reactbasic-example.tsx
const [size, setSize] = useState("M")<LabelSelector.Root value={size} onValueChange={setSize}>  <LabelSelector.Label value="Select size" />  <LabelSelector.Content>    <LabelSelector.Item value="XS" />    <LabelSelector.Item value="S" />    <LabelSelector.Item value="M" />    <LabelSelector.Item value="L" />    <LabelSelector.Item value="XL" />  </LabelSelector.Content></LabelSelector.Root>
Without Label
Reactwithout-label.tsx
const [size, setSize] = useState("L")<LabelSelector.Root value={size} onValueChange={setSize}>  <LabelSelector.Content>    <LabelSelector.Item value="XXS" />    <LabelSelector.Item value="XS" />    <LabelSelector.Item value="S" />    <LabelSelector.Item value="M" />    <LabelSelector.Item value="L" />    <LabelSelector.Item value="XL" />    <LabelSelector.Item value="XXL" />  </LabelSelector.Content></LabelSelector.Root>
Variant: Outline
Size
Reactvariant-outline.tsx
const [size, setSize] = useState("M")<LabelSelector.Root value={size} onValueChange={setSize}>  <LabelSelector.Label value="Size" />  <LabelSelector.Content>    <LabelSelector.Item value="XS" variant="outline" />    <LabelSelector.Item value="S" variant="outline" />    <LabelSelector.Item value="M" variant="outline" />    <LabelSelector.Item value="L" variant="outline" />    <LabelSelector.Item value="XL" variant="outline" />  </LabelSelector.Content></LabelSelector.Root>
Variant: Ghost
Size
Reactvariant-ghost.tsx
const [size, setSize] = useState("M")<LabelSelector.Root value={size} onValueChange={setSize}>  <LabelSelector.Label value="Size" />  <LabelSelector.Content>    <LabelSelector.Item value="XS" variant="ghost" />    <LabelSelector.Item value="S" variant="ghost" />    <LabelSelector.Item value="M" variant="ghost" />    <LabelSelector.Item value="L" variant="ghost" />    <LabelSelector.Item value="XL" variant="ghost" />  </LabelSelector.Content></LabelSelector.Root>
Variant: Solid
Size
Reactvariant-solid.tsx
const [size, setSize] = useState("M")<LabelSelector.Root value={size} onValueChange={setSize}>  <LabelSelector.Label value="Size" />  <LabelSelector.Content>    <LabelSelector.Item value="XS" variant="solid" />    <LabelSelector.Item value="S" variant="solid" />    <LabelSelector.Item value="M" variant="solid" />    <LabelSelector.Item value="L" variant="solid" />    <LabelSelector.Item value="XL" variant="solid" />  </LabelSelector.Content></LabelSelector.Root>
Size: Small
Size
Reactsize-small.tsx
const [size, setSize] = useState("M")<LabelSelector.Root value={size} onValueChange={setSize}>  <LabelSelector.Label value="Size" />  <LabelSelector.Content>    <LabelSelector.Item value="XS" size="sm" />    <LabelSelector.Item value="S" size="sm" />    <LabelSelector.Item value="M" size="sm" />    <LabelSelector.Item value="L" size="sm" />    <LabelSelector.Item value="XL" size="sm" />  </LabelSelector.Content></LabelSelector.Root>
Size: Large
Size
Reactsize-large.tsx
const [size, setSize] = useState("M")<LabelSelector.Root value={size} onValueChange={setSize}>  <LabelSelector.Label value="Size" />  <LabelSelector.Content>    <LabelSelector.Item value="XS" size="lg" />    <LabelSelector.Item value="S" size="lg" />    <LabelSelector.Item value="M" size="lg" />    <LabelSelector.Item value="L" size="lg" />    <LabelSelector.Item value="XL" size="lg" />  </LabelSelector.Content></LabelSelector.Root>
Rounded: Full
Size
Reactrounded-full.tsx
const [size, setSize] = useState("M")<LabelSelector.Root value={size} onValueChange={setSize}>  <LabelSelector.Label value="Size" />  <LabelSelector.Content>    <LabelSelector.Item value="XS" rounded="full" />    <LabelSelector.Item value="S" rounded="full" />    <LabelSelector.Item value="M" rounded="full" />    <LabelSelector.Item value="L" rounded="full" />    <LabelSelector.Item value="XL" rounded="full" />  </LabelSelector.Content></LabelSelector.Root>
Rounded: None
Size
Reactrounded-none.tsx
const [size, setSize] = useState("M")<LabelSelector.Root value={size} onValueChange={setSize}>  <LabelSelector.Label value="Size" />  <LabelSelector.Content>    <LabelSelector.Item value="XS" rounded="none" />    <LabelSelector.Item value="S" rounded="none" />    <LabelSelector.Item value="M" rounded="none" />    <LabelSelector.Item value="L" rounded="none" />    <LabelSelector.Item value="XL" rounded="none" />  </LabelSelector.Content></LabelSelector.Root>
Custom Gap Spacing
Size
Reactcustom-gap.tsx
const [size, setSize] = useState("M")<LabelSelector.Root value={size} onValueChange={setSize}>  <LabelSelector.Label value="Size" />  <LabelSelector.Content className="gap-4">    <LabelSelector.Item value="XS" />    <LabelSelector.Item value="S" />    <LabelSelector.Item value="M" />    <LabelSelector.Item value="L" />    <LabelSelector.Item value="XL" />  </LabelSelector.Content></LabelSelector.Root>
Custom Size - Larger Items
Plan
Reactcustom-size.tsx
const [variant, setVariant] = useState("pro")<LabelSelector.Root value={variant} onValueChange={setVariant}>  <LabelSelector.Label value="Plan" />  <LabelSelector.Content className="gap-3">    <LabelSelector.Item value="basic" label="Basic" className="min-w-[5rem] h-12 text-base" />    <LabelSelector.Item value="pro" label="Pro" className="min-w-[5rem] h-12 text-base" />    <LabelSelector.Item value="enterprise" label="Enterprise" className="min-w-[5rem] h-12 text-base" />  </LabelSelector.Content></LabelSelector.Root>
With Disabled Option
Select Size
Reactdisabled-option.tsx
<LabelSelector.Root defaultValue="M">  <LabelSelector.Label value="Select Size" />  <LabelSelector.Content>    <LabelSelector.Item value="XS" />    <LabelSelector.Item value="S" />    <LabelSelector.Item value="M" />    <LabelSelector.Item value="L" disabled />    <LabelSelector.Item value="XL" />  </LabelSelector.Content></LabelSelector.Root>
Long Labels
Billing
Reactlong-labels.tsx
const [plan, setPlan] = useState("monthly")<LabelSelector.Root value={plan} onValueChange={setPlan}>  <LabelSelector.Label value="Billing" />  <LabelSelector.Content className="gap-2">    <LabelSelector.Item value="monthly" label="Monthly" className="min-w-[6rem]" />    <LabelSelector.Item value="quarterly" label="Quarterly" className="min-w-[6rem]" />    <LabelSelector.Item value="annually" label="Annually" className="min-w-[6rem]" />  </LabelSelector.Content></LabelSelector.Root>
Numeric Values
EU Size
Reactnumeric-values.tsx
<LabelSelector.Root defaultValue="38">  <LabelSelector.Label value="EU Size" />  <LabelSelector.Content className="gap-2">    <LabelSelector.Item value="36" />    <LabelSelector.Item value="37" />    <LabelSelector.Item value="38" />    <LabelSelector.Item value="39" />    <LabelSelector.Item value="40" />    <LabelSelector.Item value="41" />    <LabelSelector.Item value="42" />    <LabelSelector.Item value="43" />  </LabelSelector.Content></LabelSelector.Root>
Vertical Layout
Shirt Size
Reactvertical-layout.tsx
<LabelSelector.Root defaultValue="M" className="flex-col items-start">  <LabelSelector.Label value="Shirt Size" />  <LabelSelector.Content className="gap-2">    <LabelSelector.Item value="XS" />    <LabelSelector.Item value="S" />    <LabelSelector.Item value="M" />    <LabelSelector.Item value="L" />    <LabelSelector.Item value="XL" />  </LabelSelector.Content></LabelSelector.Root>

Features

  • Built on Radix UI Radio Group primitives for accessibility
  • Composable architecture with separate Root, Label, Content, and Item components
  • Text label display with customizable values
  • Multiple visual variants: default, outline, ghost, and solid
  • Three size options: sm, default, and lg
  • Configurable border radius: none, sm, md, lg, and full
  • Visual selection state with border and background color changes
  • Support for disabled states
  • Flexible layout options (horizontal and vertical)
  • Built with class-variance-authority for consistent variant handling
  • Smooth transitions and hover effects
  • Keyboard navigation and focus management
  • Support for separate display labels and internal values
  • Fully typed with TypeScript

Component Props

LabelSelector.Root

  • value - string - Currently selected value
  • onValueChange - (value: string) => void - Callback when value changes
  • defaultValue - string - Default selected value (uncontrolled)
  • className - string - Override default container styles

LabelSelector.Label

  • value - string (required) - The label text to display
  • className - string

LabelSelector.Content

  • className - string - Useful for customizing gap spacing
  • children - React.ReactNode - LabelSelector.Item components

LabelSelector.Item

  • value - string (required) - The internal value for this option
  • label - string - The display label (defaults to value if not provided)
  • variant - "default" | "outline" | "ghost" | "solid" - Visual style variant (default: "default")
  • size - "sm" | "default" | "lg" - Size of the item (default: "default")
  • rounded - "none" | "sm" | "md" | "lg" | "full" - Border radius (default: "lg")
  • disabled - boolean - Whether the item is disabled
  • className - string - Additional custom styles

Use Cases

  • Product size selection (clothing, shoes, accessories)
  • Plan or tier selection
  • Billing frequency options
  • Variant selection (colors as text, materials, etc.)
  • Quantity or amount selection
  • Any scenario requiring labeled options in a compact format