Back to Discussions & Q&A
Verified Solution
Accepted Solutionradix a11y
How to handle Radix Select empty value reserved sentinel without hydration error?
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@avinash
Core MaintainerVerified CreatorDesign QA Expert
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)