Radio Group
An accessible single-select group with roving tabindex and full keyboard support.
Basic Radio Group
Click or use Up / Down arrow keys to navigate. Disabled radios are skipped.
<BitBhRadioGroup DefaultValue="medium" class="flex flex-col gap-2.5 data-orientation-horizontal:flex-row data-orientation-horizontal:gap-5">
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="small"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Small</span>
</label>
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="medium"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Medium</span>
</label>
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="large"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Large</span>
</label>
</BitBhRadioGroup>Horizontal Orientation
Set Vertical="false". The data-orientation-horizontal: variant flips the layout.
<BitBhRadioGroup Vertical="false" DefaultValue="card" class="flex flex-col gap-2.5 data-orientation-horizontal:flex-row data-orientation-horizontal:gap-5">
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="card"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Card</span>
</label>
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="bank"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Bank</span>
</label>
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="paypal"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>PayPal</span>
</label>
</BitBhRadioGroup>Disabled Radio
Arrow-key navigation skips disabled radios automatically.
<BitBhRadioGroup DefaultValue="standard" class="flex flex-col gap-2.5 data-orientation-horizontal:flex-row data-orientation-horizontal:gap-5">
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="standard"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Standard shipping (3–5 days)</span>
</label>
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="express"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Express shipping (1–2 days)</span>
</label>
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="same-day" Disabled="true"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Same-day shipping (unavailable in your region)</span>
</label>
</BitBhRadioGroup>Card-style options
Use the rich has-[] selector to highlight the wrapper based on the inner radio state.
<BitBhRadioGroup DefaultValue="pro" class="flex flex-col gap-2.5 w-full max-w-md">
<label class="flex items-center gap-3.5 rounded-lg border border-zinc-200 px-4 py-3.5 cursor-pointer transition-colors has-[[data-state=checked]]:border-blue-600 has-[[data-state=checked]]:bg-blue-50">
<BitBhRadio Value="free"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<div class="flex flex-col gap-0.5">
<strong class="text-sm text-zinc-900">Free</strong>
<span class="text-xs text-zinc-500">Up to 3 projects.</span>
</div>
</label>
<label class="flex items-center gap-3.5 rounded-lg border border-zinc-200 px-4 py-3.5 cursor-pointer transition-colors has-[[data-state=checked]]:border-blue-600 has-[[data-state=checked]]:bg-blue-50">
<BitBhRadio Value="pro"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<div class="flex flex-col gap-0.5">
<strong class="text-sm text-zinc-900">Pro — $9 / mo</strong>
<span class="text-xs text-zinc-600">Unlimited projects, priority support.</span>
</div>
</label>
<label class="flex items-center gap-3.5 rounded-lg border border-zinc-200 px-4 py-3.5 cursor-pointer transition-colors has-[[data-state=checked]]:border-blue-600 has-[[data-state=checked]]:bg-blue-50">
<BitBhRadio Value="team"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<div class="flex flex-col gap-0.5">
<strong class="text-sm text-zinc-900">Team — $29 / mo</strong>
<span class="text-xs text-zinc-500">For groups, with shared workspaces.</span>
</div>
</label>
</BitBhRadioGroup>Controlled
Drive selection externally.
Selected: green
<div class="flex flex-col gap-4 w-full">
<div class="flex flex-wrap items-center gap-3">
<BitBhButton OnClick='() => selectedColor = "red"' class="inline-flex items-center gap-2 rounded-lg border border-zinc-200 bg-white px-3 py-1.5 text-sm font-medium text-zinc-900 cursor-pointer hover:bg-zinc-100">Red</BitBhButton>
<BitBhButton OnClick='() => selectedColor = "green"' class="inline-flex items-center gap-2 rounded-lg border border-zinc-200 bg-white px-3 py-1.5 text-sm font-medium text-zinc-900 cursor-pointer hover:bg-zinc-100">Green</BitBhButton>
<BitBhButton OnClick='() => selectedColor = "blue"' class="inline-flex items-center gap-2 rounded-lg border border-zinc-200 bg-white px-3 py-1.5 text-sm font-medium text-zinc-900 cursor-pointer hover:bg-zinc-100">Blue</BitBhButton>
<span class="text-sm text-zinc-500">Selected: <strong class="text-zinc-900">@(selectedColor ?? "(none)")</strong></span>
</div>
<BitBhRadioGroup Value="@selectedColor" OnValueChange="v => selectedColor = v" class="flex flex-col gap-2.5 data-orientation-horizontal:flex-row data-orientation-horizontal:gap-5">
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="red"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Red</span>
</label>
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="green"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Green</span>
</label>
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="blue"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Blue</span>
</label>
</BitBhRadioGroup>
</div>
@code {
private string? selectedColor = "green";
}Form Submission
Set Name to render a hidden input with the current value.
<form @onsubmit="HandleFormSubmit" @onsubmit:preventDefault="true" class="flex flex-col items-start gap-3">
<BitBhRadioGroup Name="size" DefaultValue="m" class="flex flex-col gap-2.5 data-orientation-horizontal:flex-row data-orientation-horizontal:gap-5">
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="s"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Small</span>
</label>
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="m"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Medium</span>
</label>
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhRadio Value="l"
class="inline-flex h-[1.15rem] w-[1.15rem] flex-shrink-0 items-center justify-center rounded-full border border-zinc-300 bg-white cursor-pointer transition-colors outline-none hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-checked:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="r">
@if (r.IsChecked) { <span class="h-2 w-2 rounded-full bg-blue-600"></span> }
</Template>
</BitBhRadio>
<span>Large</span>
</label>
</BitBhRadioGroup>
<button type="submit" class="inline-flex items-center gap-2 rounded-lg border border-blue-600 bg-blue-600 px-4 py-2 text-sm font-medium text-white cursor-pointer hover:bg-blue-700">Submit</button>
@if (lastSubmitted is not null)
{
<span class="text-sm text-zinc-500">@lastSubmitted</span>
}
</form>
@code {
private string? lastSubmitted;
private void HandleFormSubmit() =>
lastSubmitted = "(submitted — the form posts size=<selected value>)";
}