Back to Discussions & Q&A
Accepted Solutionradix a11y

How to handle Radix Select empty value reserved sentinel without hydration error?

Elena Rostova
Elena Rostova@elenarostova
Design QA ExpertVerified Creator
•Feb 14, 2026
When using Radix Select, passing `value=""` triggers a runtime error or unexpected empty sentinel behavior. What is the canonical pattern in @shavin/ui to represent an unselected state with placeholder text?
Reproduction / Context
// ❌ Avoid empty string values
<Select.Item value="">Select option...</Select.Item>

// ✅ Canonical @shavin/ui pattern
<Select.Root value={value || undefined} onValueChange={setValue}>
  <Select.Trigger placeholder="Select an option" />
  <Select.Content>
    <Select.Item value="standard">Standard Plan</Select.Item>
    <Select.Item value="pro">Pro Plan</Select.Item>
  </Select.Content>
</Select.Root>
1280 total views

1 Community Answers

Avinash Bussa
Core MaintainerVerified CreatorDesign QA Expert
Verified Solution
Radix UI reserves `""` internally. In `@shavin/ui`, `Select` primitives accept `undefined` for empty controlled states, and the trigger handles the `placeholder` prop natively without requiring a dummy item node. Also remember to keep `Select.Viewport` inside `Select.Content` for smooth touch scrolling.
Solution Code Snippet
import { Select } from "@shavin/ui";

export function PlanSelector({ value, onChange }: { value?: string; onChange: (v: string) => void }) {
  return (
    <Select value={value} onValueChange={onChange} placeholder="Choose your billing tier">
      <Select.Item value="starter">Starter — $19/mo</Select.Item>
      <Select.Item value="growth">Growth — $49/mo</Select.Item>
      <Select.Item value="scale">Scale — $99/mo</Select.Item>
    </Select>
  );
}
Feb 14
Post an Answer(Active: @avinash)