Radio - Elements ​
Radios allow users to select a single option from a list of choices.
Accessibility ​
Usage ​
A radio input typically consists of two components:
<w-radio-group>- A grouping wrapper that manages labeling, help text, roving keyboard focus, and validation for child radios.<w-radio>- A single radio with required and invalid states.
In advanced cases you may use <w-radio> without <w-radio-group>. If you're unsure what's correct in your case, always wrap <w-radio> in a <w-radio-group>.
The components automatically handle:
- Form integration and constraint validation
- Required state handling with validation messages
- Accessibility attributes, keyboard interaction, and labeling
<w-radio-group label="Select an option" name="usage">
<w-radio value="one">Option 1</w-radio>
<w-radio value="two">Option 2</w-radio>
<w-radio value="three">Option 3</w-radio>
</w-radio-group>Validation ​
Set the invalid attribute to display a radio group as invalid, for example if nothing was selected and the group was required.
invalid can be paired with help-text to provide feedback to the user about how to correct the error. However, since the invalid + required use case is so common you can omit help-text to use a generic built-in one.
<w-radio-group label="Select an option" name="usage" required invalid>
<w-radio value="one">Option 1</w-radio>
<w-radio value="two">Option 2</w-radio>
<w-radio value="three">Option 3</w-radio>
</w-radio-group>Examples ​
<w-radio-group label="Select an option" name="examples">
<w-radio value="one">Option 1</w-radio>
<w-radio value="two">Option 2</w-radio>
<w-radio value="three">Option 3</w-radio>
</w-radio-group>Optional ​
Add the optional prop to <w-radio-group> to indicate that the user doesn't have to pick an option.
<w-radio-group label="Select an option" name="optional" optional>
<w-radio value="one">Option 1</w-radio>
<w-radio value="two">Option 2</w-radio>
<w-radio value="three">Option 3</w-radio>
</w-radio-group>Help text ​
Use help-text to give additional context when the label and options are not enough.
<w-radio-group label="Select an option" name="help" help-text="Pick whichever you like">
<w-radio value="one">Option 1</w-radio>
<w-radio value="two">Option 2</w-radio>
<w-radio value="three">Option 3</w-radio>
</w-radio-group>Disabled ​
Keep in mind that using disabled is an anti-pattern.
There will always be users who don't understand why an element is disabled, or users who can't even see that it is disabled because of poor lighting conditions or other reasons.
Please consider more informative alternatives before choosing to use disabled on an element.
<w-radio-group label="Select an option" name="disabled" disabled>
<w-radio value="one">Option 1</w-radio>
<w-radio value="two">Option 2</w-radio>
<w-radio value="three">Option 3</w-radio>
</w-radio-group>Radio and Radio Group Styling ​
This document covers the styling API for both <w-radio> (individual radio buttons) and <w-radio-group> (the container that manages them).
Quick Start ​
<w-radio-group label="Choose a size" name="size">
<w-radio value="small">Small</w-radio>
<w-radio value="medium">Medium</w-radio>
<w-radio value="large">Large</w-radio>
</w-radio-group>Customize via component tokens:
/* Style all radio groups in a section */
.settings {
--w-c-radio-group-gap: 12px;
--w-c-radio-size: 2.4rem;
}Styling Philosophy ​
Before customizing, remember that changing defaults can create inconsistent experiences. Prefer the defaults.
- Component tokens for size, spacing, color, and state styling
- Parts only for small, one-off tweaks
- Avoid relying on internal class names
Radio Group (<w-radio-group>) ​
Parts ​
| Part | Targets | Use Case |
|---|---|---|
form-control | The <fieldset> wrapper | Outer container tweaks |
form-control-label | The group label element | Label typography overrides |
form-control-input | Container for radio buttons | Adjust layout/flow of radios |
help-text | Help text / error message | Style hint text |
Example:
w-radio-group::part(form-control-label) {
text-transform: uppercase;
}
w-radio-group::part(form-control-input) {
flex-direction: row; /* horizontal radios */
}Component Tokens ​
Label ​
| Token | Purpose | Default |
|---|---|---|
--w-c-radio-group-label-font-size | Label font size | var(--w-font-size-s) |
--w-c-radio-group-label-line-height | Label line height | var(--w-line-height-s) |
--w-c-radio-group-label-font-weight | Label font weight | 700 |
--w-c-radio-group-label-color | Label text color | var(--w-s-color-text) |
--w-c-radio-group-label-color-disabled | Label color when disabled | var(--w-s-color-text-disabled) |
--w-c-radio-group-label-padding-bottom | Space below label | 16px |
Optional Indicator ​
| Token | Purpose | Default |
|---|---|---|
--w-c-radio-group-optional-font-weight | "Optional" text weight | 400 |
--w-c-radio-group-optional-color | "Optional" text color | var(--w-s-color-text-subtle) |
--w-c-radio-group-optional-margin-inline-start | Space before "Optional" | 0.5rem |
Radio Spacing ​
| Token | Purpose | Default |
|---|---|---|
--w-c-radio-group-gap | Gap between radio buttons | 16px |
Help Text ​
| Token | Purpose | Default |
|---|---|---|
--w-c-radio-group-help-text-margin-block-start | Space above help text | 16px |
--w-c-radio-group-help-text-font-size | Help text font size | var(--w-font-size-xs) |
--w-c-radio-group-help-text-line-height | Help text line height | var(--w-line-height-xs) |
--w-c-radio-group-help-text-color | Help text color | var(--w-s-color-text-subtle) |
--w-c-radio-group-help-text-color-disabled | Help text color when disabled | var(--w-s-color-text-disabled) |
--w-c-radio-group-help-text-color-error | Help text color when invalid | var(--w-s-color-text-negative) |
Example:
w-radio-group {
--w-c-radio-group-gap: 12px;
--w-c-radio-group-label-font-weight: 600;
--w-c-radio-group-help-text-color: var(--w-s-color-text);
}Individual Radio (<w-radio>) ​
Parts ​
| Part | Targets | Use Case |
|---|---|---|
base | Wrapper containing control and label | Container-level adjustments |
control | Radio control (circle) | Alignment or sizing tweaks |
label | Label content | Typography overrides |
Example:
w-radio::part(label) {
font-weight: 600;
}
w-radio::part(control) {
margin-top: 1px;
}Component Tokens ​
Layout & Size ​
| Token | Purpose | Default |
|---|---|---|
--w-c-radio-gap | Space between control and label | 8px |
--w-c-radio-size | Width/height of control | 2rem |
--w-c-radio-radius | Border radius | 50% |
--w-c-radio-border-width | Border width | 1px |
--w-c-radio-checked-border-width | Border width when checked | 0.6rem |
Colors ​
| Token | Purpose | Default |
|---|---|---|
--w-c-radio-bg | Control background | var(--w-s-color-background) |
--w-c-radio-border-color | Control border color | var(--w-s-color-border-strong) |
--w-c-radio-border-color-checked | Border when checked | var(--w-s-color-border-selected) |
--w-c-radio-border-color-invalid | Border when invalid | var(--w-s-color-border-negative) |
--w-c-radio-label-color | Label text color | currentColor |
Disabled State ​
| Token | Purpose | Default |
|---|---|---|
--w-c-radio-bg-disabled | Background when disabled | var(--w-s-color-background-disabled-subtle) |
--w-c-radio-border-color-disabled | Border when disabled | var(--w-s-color-border-disabled) |
--w-c-radio-label-color-disabled | Label color when disabled | var(--w-s-color-text-disabled) |
--w-c-radio-cursor-disabled | Cursor when disabled | not-allowed |
Typography ​
| Token | Purpose | Default |
|---|---|---|
--w-c-radio-label-font-size | Label font size | var(--w-font-size-m) |
--w-c-radio-label-line-height | Label line height | var(--w-line-height-m) |
Focus ​
| Token | Purpose | Default |
|---|---|---|
--w-c-radio-outline-width | Focus outline width | 2px |
--w-c-radio-outline-color | Focus outline color | var(--w-s-color-border-focus) |
--w-c-radio-outline-offset | Focus outline offset | var(--w-outline-offset, 1px) |
Interaction ​
| Token | Purpose | Default |
|---|---|---|
--w-c-radio-cursor | Cursor in enabled state | pointer |
Motion ​
| Token | Purpose | Default |
|---|---|---|
--w-c-radio-transition | Transition for control | border-color 150ms, border-width 150ms, background-color 150ms |
Note: Transitions automatically disable when prefers-reduced-motion: reduce is active.
Complete Examples ​
Horizontal Radio Group ​
w-radio-group::part(form-control-input) {
flex-direction: row;
flex-wrap: wrap;
}Larger Radio Buttons ​
w-radio {
--w-c-radio-size: 2.4rem;
--w-c-radio-checked-border-width: 0.8rem;
}Custom Colors ​
w-radio {
--w-c-radio-border-color-checked: var(--w-s-color-border-success);
}Tighter Spacing ​
w-radio-group {
--w-c-radio-group-gap: 8px;
--w-c-radio-group-label-padding-bottom: 8px;
}Architecture Note ​
Radio-group uses <fieldset> which is the semantic HTML element for grouping form controls. Note that <w-checkbox-group> currently uses <div> instead - this inconsistency may be addressed in a future major version to align both components on the more accessible <fieldset> approach.
<w-radio-group> API ​
Unless otherwise noted all properties are HTML attributes (as opposed to JavaScript object properties).
Properties ​
| Name | Type | Default | Summary |
|---|---|---|---|
| disabled | boolean | false | Disables the radio group and all child radios. |
| help-text | string | "" | Help text for the radio group. |
| invalid | boolean | false | Marks the radio group as invalid. |
| label | string | "" | Label for the radio group. |
| name | string | null | null | The name of the select when submitting the form. |
| optional | boolean | false | Whether to show optional text next to the label. |
| required | boolean | false | Makes selecting a radio in the the group required. |
Property Details ​
disabled ​
Disables the radio group and all child radios.
- Type:
boolean - Default:
false
help-text ​
Help text for the radio group.
If you set required and invalid the group gets a default error message, but you can override it with this attribute.
- Type:
string - Default:
""
invalid ​
Marks the radio group as invalid.
- Type:
boolean - Default:
false
label ​
Label for the radio group.
- Type:
string - Default:
""
name ​
The name of the select when submitting the form.
- Type:
string | null - Default:
null
optional ​
Whether to show optional text next to the label.
- Type:
boolean - Default:
false
required ​
Makes selecting a radio in the the group required.
- Type:
boolean - Default:
false
<w-radio> API ​
Properties ​
| Name | Type | Default | Summary |
|---|---|---|---|
| checked | boolean | false | Draws the radio in a checked state (reflected to attribute). |
| disabled | boolean | false | Disables the radio. |
| invalid | boolean | false | Draws the radio in an invalid state. |
| name | string | - | The name of the radio, submitted as a name/value pair with form data. |
| required | boolean | false | Makes the radio a required field. |
| value | string | null | null | The radio's value. When selected, the radio group will receive this value. |
Property Details ​
checked ​
Draws the radio in a checked state (reflected to attribute).
- Type:
boolean - Default:
false
disabled ​
Disables the radio.
- Type:
boolean - Default:
false
invalid ​
Draws the radio in an invalid state.
- Type:
boolean - Default:
false
name ​
The name of the radio, submitted as a name/value pair with form data.
- Type:
string - Default:
-
required ​
Makes the radio a required field.
- Type:
boolean - Default:
false
value ​
The radio's value. When selected, the radio group will receive this value.
- Type:
string | null - Default:
null
Questions? ​
Feel free to ask any questions on usage in the Warp DS Slack channel: #warp-design-system