Radio
A form control for single-select lists. Multiple radios sharing the same name form a mutually exclusive group.
Basic Usage
With Hint
€9 billed each month
€90 per year — save 2 months
Card Variant
variant="card" turns each option into a bordered, fully-clickable card that highlights when selected — perfect for pricing tiers and plan pickers. The card reacts to its own input via CSS :has(), no JavaScript needed.
Sizes
sm, md (default), and lg scale the circle and its inner dot together, matching the size prop on Checkbox and Toggle.
Disabled
With Error
When validation fails, apply the error prop to one of the radios (usually the last) so the message appears under the group. Wrap the group in a native <fieldset> + <legend> for the WCAG-standard group-label semantics — screen readers announce the legend before each radio in the set.
Livewire Integration
Bind every radio in the group to the same Livewire property via wire:model.live. The radios share a name so the browser already groups them; wire:model synchronizes the chosen value back to the component.
<x-wirekit::radio name="plan" value="free" label="Free" wire:model.live="selectedPlan" />
<x-wirekit::radio name="plan" value="pro" label="Pro" wire:model.live="selectedPlan" />
Props
| Prop | Type | Default | Description |
|---|---|---|---|
label |
string|null | null |
Text next to the radio |
hint |
string|null | null |
Helper text below |
error |
string|null | null |
Error message (also triggers aria-invalid) |
value |
string|null | null |
Value submitted when selected (required for grouping) |
size |
string | 'md' |
Circle size — sm, md, or lg |
variant |
string | 'default' |
default (inline) or card (the whole bordered card is the selectable target) |
scope |
string|null | null |
Scoped personalization name |
The id is auto-generated as {name}-{value} when both are given, ensuring unique IDs within a radio group.
Accessibility
- Native
<input type="radio">— browser provides full keyboard support:- Arrow keys navigate between options within the same
namegroup - Space selects the focused radio
- Tab moves focus to the first/checked radio of the next group
- Arrow keys navigate between options within the same
- The visual circle and inner dot are decorative (
aria-hidden="true"). - For a screen-reader-announced group label, wrap related radios in a native
<fieldset>with a<legend>— this is the WCAG-recommended pattern for grouped form controls and is announced before each radio in the set:
<fieldset>
<legend>Choose a plan</legend>
<x-wirekit::radio name="plan" value="free" label="Free" />
<x-wirekit::radio name="plan" value="pro" label="Pro" />
</fieldset>
If <fieldset>'s default border or spacing is undesirable, reset it with style="border: 0; padding: 0;" rather than reaching for a <div role="group"> ARIA fallback — the native element wins on assistive-technology compatibility.
Keyboard Interaction
| Key | Action |
|---|---|
Tab |
Move focus into the radio group |
ArrowUp / ArrowLeft |
Move focus and selection to the previous radio in the group |
ArrowDown / ArrowRight |
Move focus and selection to the next radio in the group |
Space |
Select the focused radio (when entering the group with Tab) |
Pitfalls
- Don't omit
name="..."on a radio group. All radios in the same group MUST sharename— otherwise multi-selection is possible and the form posts unexpected data. - Don't use a radio group for binary on/off. A
<x-wirekit::toggle>is the right pattern; radios are for ≥3 mutually exclusive choices.
Design Tokens
| Token | Purpose |
|---|---|
--color-wk-accent |
Inner dot + active border |
--color-wk-bg-input |
Circle background |
--color-wk-border-strong / --color-wk-border-error |
Circle border |
--color-wk-ring |
Focus ring |