Skip to content

Radio

import { Radio, RadioGroup } from '@delightstack/components';

The RadioGroup is re-exported from the same module. The context type is also available:

import type { RadioGroupContext } from '@delightstack/components';
<script>
import { Radio, RadioGroup } from '@delightstack/components';
let selectedSize = $state('medium');
</script>
<RadioGroup bind:value={selectedSize} name="size" label="Size">
<Radio value="small" label="Small" />
<Radio value="medium" label="Medium" />
<Radio value="large" label="Large" />
</RadioGroup>
Size
Small
Medium
Large
View code
<RadioGroup name="size" label="Size">
<Radio value="small" label="Small" />
<Radio value="medium" label="Medium" />
<Radio value="large" label="Large" />
</RadioGroup>
Preference
Yes
No
Maybe
View code
<RadioGroup horizontal name="preference" label="Preference">
<Radio value="yes" label="Yes" />
<Radio value="no" label="No" />
<Radio value="maybe" label="Maybe" />
</RadioGroup>
Select a plan
Free Basic features, forever free
Pro Advanced features, $10/mo
Enterprise Custom pricing
View code
<RadioGroup name="plan" label="Select a plan">
<Radio value="free" label="Free" description="Basic features, forever free" />
<Radio value="pro" label="Pro" description="Advanced features, $10/mo" />
<Radio value="enterprise" label="Enterprise" description="Custom pricing" />
</RadioGroup>
Agreement
I agree
I disagree
Please select an option
View code
<script>
import { Radio, RadioGroup } from '@delightstack/components';
let agreement = $state('');
</script>
<RadioGroup
bind:value={agreement}
required
error={!agreement ? 'Please select an option' : ''}
name="agreement"
label="Agreement"
>
<Radio value="agree" label="I agree" />
<Radio value="disagree" label="I disagree" />
</RadioGroup>

A Radio can be used without a RadioGroup by managing checked directly.

Option 1
Option 2

Selected: option1

View code
<script>
import { Radio } from '@delightstack/components';
let selected = $state('option1');
</script>
<Radio
value="option1"
checked={selected === 'option1'}
onchange={() => selected = 'option1'}
label="Option 1"
/>
<Radio
value="option2"
checked={selected === 'option2'}
onchange={() => selected = 'option2'}
label="Option 2"
/>
Small (size 0)
Option A
Option B
Default (size 1)
Option A
Option B
Medium (size 2)
Option A
Option B
Large (size 3)
Option A
Option B
View code
<RadioGroup bind:value={val0} name="size0" size="0" label="Small (size 0)">
<Radio value="a" label="Option A" />
<Radio value="b" label="Option B" />
</RadioGroup>
<RadioGroup bind:value={val1} name="size1" size="1" label="Default (size 1)">
<Radio value="a" label="Option A" />
<Radio value="b" label="Option B" />
</RadioGroup>
<RadioGroup bind:value={val2} name="size2" size="2" label="Medium (size 2)">
<Radio value="a" label="Option A" />
<Radio value="b" label="Option B" />
</RadioGroup>
<RadioGroup bind:value={val3} name="size3" size="3" label="Large (size 3)">
<Radio value="a" label="Option A" />
<Radio value="b" label="Option B" />
</RadioGroup>
PropTypeDefaultDescription
valuestring''Option value (bindable)
checkedbooleanfalseSelected state, bindable (for standalone use)
disabledbooleanfalseDisable this option
size'0' | '1' | '2' | '3''1'Radio size
labelstring''Label text
descriptionstring''Helper text below label
tooltipstring''Tooltip text on hover
densebooleanfalseTighter label/circle spacing
comfortablebooleanfalseMore label/circle spacing
idstringautoElement ID
namestring''Form field name
classstring''Additional CSS classes
PropTypeDefaultDescription
valuestring''Selected value, bindable
namestring''Shared group name
disabledbooleanfalseDisable all radio options
size'0' | '1' | '2' | '3''1'Size for all child radios
horizontalbooleanfalseHorizontal layout
labelstring''Group label
errorstring''Group-level error message
requiredbooleanfalseSelection is required
densebooleanfalseCompact spacing between options
comfortablebooleanfalseRelaxed spacing between options
idstringautoElement ID
classstring''Additional CSS classes
childrenSnippet-Radio children
EventDetailDescription
onchange{ value: string }Selection changed
EventDetailDescription
onchange{ value: string }Selection changed
interface RadioGroupContext {
name: string;
value: string;
disabled: boolean;
size: '0' | '1' | '2' | '3';
select: (value: string) => void;
}
  • Hidden native <input type="radio"> for form submission and semantics
  • aria-checked reflects selection state
  • aria-describedby for description text
  • aria-required when required
  • RadioGroup rendered as <div role="radiogroup"> with aria-labelledby
  • Full keyboard navigation: Arrow keys move between options within a group, Tab moves between groups
  • Focus ring visible only on keyboard focus (:focus-visible)
  • Selection dot animates with scale() for satisfying visual feedback