WRadio
Controlled radio button. Composes WAnchor (interaction state) + WDiv (outer ring shell) + WDiv (inner filled indicator). Drives the selected: state prefix when value == groupValue, mirroring how WCheckbox drives checked:.
Mutually-exclusive group behavior is the caller's responsibility: pass the same groupValue to every WRadio in a group and update it through onChanged.
Table of Contents
Basic Usage
WRadio(
value: 'light',
groupValue: _theme,
onChanged: (val) => setState(() => _theme = val),
className: '''
w-5 h-5 rounded-full border border-gray-300 dark:border-gray-600
flex items-center justify-center
selected:border-blue-500 dark:selected:border-blue-400
hover:border-blue-400 dark:hover:border-blue-300
''',
indicatorClassName: 'w-2.5 h-2.5 rounded-full bg-blue-500 dark:bg-blue-400',
)
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value |
T |
Required | The value this radio represents. |
groupValue |
T? |
Required | The currently selected value for the group. When value == groupValue, selected: state activates. |
onChanged |
ValueChanged |
null |
Called with value when this radio is tapped and not already selected. Omit or pass null for a non-interactive radio. |
className |
String? |
null |
Utility classes for the outer ring shell. Defaults to 'w-5 h-5 rounded-full border border-gray-300 flex items-center justify-center selected:border-primary-500' when null. |
indicatorClassName |
String? |
null |
Utility classes for the inner filled dot (visible only when selected). Defaults to 'w-2.5 h-2.5 rounded-full bg-primary selected:opacity-100' when null. |
disabled |
bool |
false |
Blocks tap and activates the disabled: prefix. |
states |
Set |
null |
Extra custom states merged with built-in selected and disabled. |
semanticLabel |
String? |
null |
Accessible label for the Semantics node. Required on icon-only radios. |
Constructor
WRadio({
Key? key,
required T value,
required T? groupValue,
ValueChanged? onChanged,
String? className,
String? indicatorClassName,
bool disabled = false,
Set? states,
String? semanticLabel,
})
Styling Examples
Vertical Radio Group
Each radio in the group shares the same groupValue and onChanged. The selected: prefix styles the active choice:
WRadio(
value: 'pro',
groupValue: _plan,
onChanged: (val) => setState(() => _plan = val),
className: '''
w-5 h-5 rounded-full border-2
border-gray-300 dark:border-gray-600
flex items-center justify-center
selected:border-indigo-500 dark:selected:border-indigo-400
hover:border-indigo-400 dark:hover:border-indigo-300
disabled:opacity-50
''',
indicatorClassName: '''
w-2.5 h-2.5 rounded-full
bg-indigo-500 dark:bg-indigo-400
''',
)
Horizontal Row
Arrange radios in a flex-row container for inline selection:
WDiv(
className: 'flex flex-row gap-6',
children: [
for (final option in ['light', 'dark', 'system'])
WDiv(
className: 'flex flex-row items-center gap-2',
children: [
WRadio(
value: option,
groupValue: _theme,
onChanged: (val) => setState(() => _theme = val),
className: 'w-5 h-5 rounded-full border border-gray-300 dark:border-gray-600 flex items-center justify-center selected:border-blue-500 dark:selected:border-blue-400',
indicatorClassName: 'w-2.5 h-2.5 rounded-full bg-blue-500 dark:bg-blue-400',
),
WText(option, className: 'text-sm text-gray-700 dark:text-gray-300'),
],
),
],
)
Default Fallback Styling
When className or indicatorClassName is omitted, WRadio falls back to its built-in defaults, which route through the theme primary token (blue by default; override primary in WindThemeData to rebrand). Override the classNames only when the design calls for a different tone:
// Uses built-in primary defaults (blue unless the theme's primary is overridden)
WRadio(
value: 'option',
groupValue: _value,
onChanged: (val) => setState(() => _value = val),
)