Radio button
Create consistent cross-browser and cross-device radio buttons.
On this page
- Radio button v1.4.0
You can find here the OUDS Radio button design guidelines.
Overview
Radio buttons allow user to select a single option from a set of mutually exclusive choices.
They are implemented using .radio-button-item and .control-item-* classes, see below. Browser default radio buttons are replaced with the help of the selector .control-item-indicator[type="radio"].
<fieldset class="control-items-list">
<div class="radio-button-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioDefault" name="radioBasic" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioDefault">Default radio button</label>
</div>
</div>
<div class="radio-button-item">
<div class="control-item-assets-container">
<input checked class="control-item-indicator" type="radio" value="" id="radioDefault2" name="radioBasic" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioDefault2">Checked radio button</label>
</div>
</div>
</fieldset>
Bootstrap
$enable-bootstrap-compatibility: true
This part is enabled only when $enable-bootstrap-compatibility is set to true. Read more
about Bootstrap compatibility.
<div class="form-check">
<input class="form-check-input" type="radio" value="" id="checkDefault" name="radioBasicBs" />
<label class="form-check-label" for="checkDefault">
Default radio button (Bootstrap compatible)
</label>
</div>
<div class="form-check">
<input checked class="form-check-input" type="radio" value="" id="checkChecked" name="radioBasicBs" />
<label class="form-check-label" for="checkChecked">
Checked radio button (Bootstrap compatible)
</label>
</div> Approach
Control item
Control item is an abstraction for several non-text input components, like checkbox, radio button and switch, that have similar behavior and layout. It contains an <input /> indicator, a text container for the label and an optional icon.
We use the parent element selector (:has) for all our <input /> states, like :invalid or :disabled. When combined with the .control-item-label class, we can easily style the text for each item based on the <input />’s state.
.control-item-assets-container controls the position of the .control-item-indicator and the optional icon.
.control-item-text-container contains the label and optional description and controls their positioning.
.control-item-label extend their clickable area until a .checkbox-standalone, .radio-button-standalone, .switch-standalone or a position: relative; is found in the page hierarchy. This ensures a consistent approach, whatever the DOM is. Consequently, none of the elements next to the label should be interactive.
.control-item-indicator uses customized icons to indicate checked states.
Control items list
As radio buttons are almost always grouped in a list, they should be enclosed in a <fieldset> element with a .control-items-list class, this will handle automatic error text display when one of the control items input is invalid; you can add a <legend> element as a title for the list read more.
Variants
Divider
To display a divider, add .control-item-divider to a .radio-button-item.
<fieldset class="control-items-list">
<div class="radio-button-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioDivider" name="radioDivider" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioDivider">Default radio button with divider</label>
</div>
</div>
<div class="radio-button-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioDivider2" name="radioDivider" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioDivider2">Checked radio button with divider</label>
</div>
</div>
</fieldset> Icon
The recommended way to use icons is to fill an SVG sprite file, and use currentColor for styling. If really necessary, for example when you have a lot of icons, you can use an icon font. Find out more about using icons.
To display an icon, add .control-item-assets-container with an icon (SVG or font-icon most likely) inside, as a child of a .radio-button-item.
<fieldset class="control-items-list">
<div class="radio-button-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioWithSVG" name="radioIcon" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioWithSVG">Default radio button with an SVG icon</label>
</div>
<div class="control-item-assets-container">
<svg width="1rem" height="1rem" fill="currentColor" aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</div>
<div class="radio-button-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioWithIconFont" name="radioIcon" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioWithIconFont">Checked radio button with a font-icon</label>
</div>
<div class="control-item-assets-container">
<span class="icon si si-settings" aria-hidden="true"></span>
</div>
</div>
</fieldset> Extra label
To add critical information to some of the options, add a .radio-button-extra-label as a sibling of a .control-item-label. Make sure the extra label is accessible by adding an aria-describedby attribute to the input.
<fieldset class="control-items-list">
<div class="radio-button-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioWithExtraLabelItem" aria-describedby="radioExtraLabel" name="radioExtraLabel" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioWithExtraLabelItem">Default radio button</label>
<p class="radio-button-extra-label" id="radioExtraLabel">Extra label</p>
</div>
</div>
<div class="radio-button-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioWithExtraLabelItem2" aria-describedby="radioExtraLabel2" name="radioExtraLabel" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioWithExtraLabelItem2">Checked radio button</label>
<p class="radio-button-extra-label" id="radioExtraLabel2">Extra label</p>
</div>
</div>
</fieldset> Description text
To display a description text, add a .control-item-description as a sibling of a .control-item-label. Make sure the description is accessible by adding an aria-describedby attribute to the input.
Extra label and description text can be combined, but the extra label must come first (visually and in the aria-describedby attribute).
<fieldset class="control-items-list">
<div class="radio-button-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioWithDescription" aria-describedby="radioDescription" name="radioTextDescription" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioWithDescription">Default radio button</label>
<p class="control-item-description" id="radioDescription">Description text</p>
</div>
</div>
<div class="radio-button-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioWithDescription2" aria-describedby="radioDescriptionExtraLabel radioDescription2" name="radioTextDescription" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioWithDescription2">Checked radio button</label>
<p class="radio-button-extra-label" id="radioDescriptionExtraLabel">Extra label</p>
<p class="control-item-description" id="radioDescription2">Description text</p>
</div>
</div>
</fieldset> Outlined
To display outlined radio buttons, add .radio-button-item-outlined to a .radio-button-item. If there is an outlined radio button item in a group, all its siblings should also be outlined.
<fieldset class="control-items-list">
<div class="radio-button-item radio-button-item-outlined">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioOutlined1" name="radioOutlined" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioOutlined1">Default outlined radio button</label>
</div>
</div>
<div class="radio-button-item radio-button-item-outlined">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioOutlined2" name="radioOutlined" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioOutlined2">Checked outlined radio button</label>
</div>
</div>
</fieldset> Layout
Default
It's recommended to keep radio button label to no more than three words. When space is limited or when a long label, extra label or description text is required, the text can wrap, as this is preferable to truncation. The radio button indicator and the icon will remain vertically centered, until the .control-item-assets-container reaches a defined maximum height.
<div class="row">
<div class="col-8 col-md-6 col-xl-5">
<fieldset class="control-items-list">
<div class="radio-button-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioLayout1" name="radioLayout" aria-describedby="radioLayout1ExtraLabel radioLayout1Description" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioLayout1">Label</label>
<p class="radio-button-extra-label" id="radioLayout1ExtraLabel">Extra label</p>
<p class="control-item-description" id="radioLayout1Description">Description text</p>
</div>
<div class="control-item-assets-container">
<svg width="1rem" height="1rem" fill="currentColor" aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</div>
<div class="radio-button-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioLayout2" name="radioLayout" aria-describedby="radioLayout2ExtraLabel radioLayout2Description" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioLayout2">A longer label for showing behavior in this case</label>
<p class="radio-button-extra-label" id="radioLayout2ExtraLabel">Radio button indicator and icon will stick to the top area of the component</p>
<p class="control-item-description" id="radioLayout2Description">Also a longer description text, it will also wrap at some point depending on the component width</p>
</div>
<div class="control-item-assets-container">
<svg width="1rem" height="1rem" fill="currentColor" aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</div>
</fieldset>
</div>
</div> Reverse
To reverse the component, simply add .control-item-reverse to a .radio-button-item.
<div class="row">
<div class="col-8 col-md-6 col-xl-5">
<fieldset class="control-items-list">
<div class="radio-button-item control-item-divider control-item-reverse">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioLayoutRev1" name="radioLayoutRev" aria-describedby="radioLayoutRev1ExtraLabel radioLayoutRev1Description" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioLayoutRev1">Label with reverse layout</label>
<p class="radio-button-extra-label" id="radioLayoutRev1ExtraLabel">Extra label</p>
<p class="control-item-description" id="radioLayoutRev1Description">Description text</p>
</div>
<div class="control-item-assets-container">
<svg width="1rem" height="1rem" fill="currentColor" aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</div>
<div class="radio-button-item control-item-divider control-item-reverse">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioLayoutRev2" name="radioLayoutRev" aria-describedby="radioLayoutRev2ExtraLabel radioLayoutRev2Description" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioLayoutRev2">A longer label with reverse layout for showing behavior in this case</label>
<p class="radio-button-extra-label" id="radioLayoutRev2ExtraLabel">Radio button indicator and icon will stick to the top area of the component</p>
<p class="control-item-description" id="radioLayoutRev2Description">Also a longer description text, it will also wrap at some point depending on the component width</p>
</div>
<div class="control-item-assets-container">
<svg width="1rem" height="1rem" fill="currentColor" aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</div>
</fieldset>
</div>
</div>
Bootstrap
$enable-bootstrap-compatibility: true
This part is enabled only when $enable-bootstrap-compatibility is set to true. Read more
about Bootstrap compatibility.
Put your radio buttons on the opposite side with the .form-check-reverse modifier class.
<div class="form-check form-check-reverse">
<input class="form-check-input" type="radio" value="" id="reverseCheck1" name="radioReverseBs" />
<label class="form-check-label" for="reverseCheck1">
Default reverse radio button (Bootstrap compatible)
</label>
</div>
<div class="form-check form-check-reverse">
<input class="form-check-input" type="radio" value="" id="reverseCheck2" name="radioReverseBs" checked />
<label class="form-check-label" for="reverseCheck2">
Checked reverse radio button (Bootstrap compatible)
</label>
</div> Horizontal
You can align horizontally up to three radio buttons if their labels are short, add sufficient space (for example by using .gap-small) between the controls to ensure a clear association of each labels with their corresponding indicator.
<fieldset class="control-items-list">
<div class="d-flex flex-row gap-small w-50">
<div class="radio-button-item flex-fill">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioLayoutRow1" name="radioLayoutRow" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioLayoutRow1">Option 1</label>
</div>
</div>
<div class="radio-button-item flex-fill">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioLayoutRow2" name="radioLayoutRow" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioLayoutRow2">Option 2</label>
</div>
</div>
</div>
</fieldset> States
Disabled
Add the disabled attribute to the input, then the radio button and the associated <label> are automatically styled to match with a lighter color to help indicate the input’s state.
<fieldset class="control-items-list">
<div class="radio-button-item">
<div class="control-item-assets-container">
<input disabled class="control-item-indicator" type="radio" value="" id="radioDisabled" name="radioDisabled" aria-describedby="radioDisabledExtraLabel radioDisabledDescription"/>
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioDisabled">Default disabled radio button</label>
<p class="radio-button-extra-label" id="radioDisabledExtraLabel">Extra label</p>
<p class="control-item-description" id="radioDisabledDescription">Description text</p>
</div>
</div>
<div class="radio-button-item">
<div class="control-item-assets-container">
<input disabled class="control-item-indicator" type="radio" value="" id="radioCheckedDisabled" name="radioDisabled" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioCheckedDisabled">Checked disabled radio button</label>
</div>
</div>
</fieldset>
Bootstrap
$enable-bootstrap-compatibility: true
This part is enabled only when $enable-bootstrap-compatibility is set to true. Read more
about Bootstrap compatibility.
<div class="form-check">
<input disabled class="form-check-input" type="radio" value="" id="checkDisabled" name="radioDisabledBs" />
<label class="form-check-label" for="checkDisabled">
Default disabled radio button
</label>
</div>
<div class="form-check">
<input disabled class="form-check-input" type="radio" value="" id="checkCheckedDisabled" name="radioDisabledBs" checked />
<label class="form-check-label" for="checkCheckedDisabled">
Checked disabled radio button
</label>
</div> Read only
To create a read only radio button, the input should be replaced by a span element with role="radio" and aria-disabled="true" attributes. All the radio buttons in the group must be surrounded by a container with role="radiogroup" and aria-readonly="true" attributes. This is the only way to be compliant with ARIA specifications. The radio button will be accessible to keyboard navigation and assistive technologies, thanks to aria-labelledby and tabindex, but other interactions will be prevented.
<fieldset class="control-items-list">
<div role="radiogroup" aria-readonly="true">
<div class="radio-button-item">
<div class="control-item-assets-container">
<span class="control-item-indicator" role="radio" aria-disabled="true" tabindex="0" aria-checked="false" aria-labelledby="radioReadonlyLabel" aria-describedby="radioReadonlyExtraLabel radioReadonlyDescription"></span>
</div>
<div class="control-item-text-container">
<p class="control-item-label" id="radioReadonlyLabel">Default readonly radio button</p>
<p class="radio-button-extra-label" id="radioReadonlyExtraLabel">Extra label</p>
<p class="control-item-description" id="radioReadonlyDescription">Description text</p>
</div>
</div>
<div class="radio-button-item">
<div class="control-item-assets-container">
<span class="control-item-indicator" role="radio" aria-disabled="true" tabindex="0" aria-checked="true" aria-labelledby="radioReadonlyCheckedLabel"></span>
</div>
<div class="control-item-text-container">
<p class="control-item-label" id="radioReadonlyCheckedLabel">Checked readonly radio button</p>
</div>
</div>
</div>
</fieldset> Invalid
The invalid state is the equivalent of the ‘Error’ state that you can find in the design specification.
To display an invalid radio button, add .is-invalid to a .control-item-indicator. Please take a look at our Validation page to learn more.
<fieldset class="control-items-list">
<div class="radio-button-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator is-invalid" type="radio" value="" name="radioInvalid" id="radioInvalid" aria-describedby="radioInvalidExtraLabel radioInvalidDescription radioInvalidErrorText" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioInvalid">Default invalid radio button</label>
<p class="radio-button-extra-label" id="radioInvalidExtraLabel">Extra label</p>
<p class="control-item-description" id="radioInvalidDescription">Description text</p>
</div>
</div>
<div class="radio-button-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator is-invalid" type="radio" value="" name="radioInvalid" id="radioInvalid2" aria-describedby="radioInvalid2Description radioInvalidErrorText" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioInvalid2">Checked invalid radio button</label>
<p class="control-item-description" id="radioInvalid2Description">Description text</p>
</div>
</div>
<p class="control-item-error-message" id="radioInvalidErrorText">There is an error.</p>
</fieldset>
Bootstrap
$enable-bootstrap-compatibility: true
This part is enabled only when $enable-bootstrap-compatibility is set to true. Read more
about Bootstrap compatibility.
To display an invalid radio button, add .is-invalid to a .form-check-input.
<div class="form-check">
<input class="form-check-input is-invalid" type="radio" value="" id="radioInvalidBootstrap" />
<label class="form-check-label" for="radioInvalidBootstrap">
Invalid radio
</label>
</div> Outlined
This also works for outlined variant of the component.
<fieldset class="control-items-list">
<div class="radio-button-item radio-button-item-outlined">
<div class="control-item-assets-container">
<input class="control-item-indicator is-invalid" type="radio" value="" name="outlinedInvalid" id="outlinedInvalid1" aria-describedby="radioLayoutOutlinedInvalidErrorText" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="outlinedInvalid1">Default invalid outlined radio button</label>
</div>
</div>
<div class="radio-button-item radio-button-item-outlined">
<div class="control-item-assets-container">
<input class="control-item-indicator is-invalid" type="radio" value="" name="outlinedInvalid" id="outlinedInvalid2" checked aria-describedby="radioLayoutOutlinedInvalidErrorText" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="outlinedInvalid2">Checked invalid outlined radio button</label>
</div>
</div>
<p class="control-item-error-message" id="radioLayoutOutlinedInvalidErrorText">Forbidden choice.</p>
</fieldset> Horizontal
If the layout is horizontal, the <fieldset> must enclose the flex containers so the error message is displayed under the first item.
<fieldset class="control-items-list">
<div class="d-flex flex-row gap-small w-50">
<div class="radio-button-item flex-fill">
<div class="control-item-assets-container">
<input class="control-item-indicator is-invalid" type="radio" value="" id="radioLayoutRowInvalid1" name="radioLayoutRowInvalid" aria-describedby="radioLayoutRowInvalidErrorText" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioLayoutRowInvalid1">Option 1</label>
</div>
</div>
<div class="radio-button-item flex-fill">
<div class="control-item-assets-container">
<input class="control-item-indicator is-invalid" type="radio" value="" id="radioLayoutRowInvalid2" name="radioLayoutRowInvalid" aria-describedby="radioLayoutRowInvalidErrorText" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioLayoutRowInvalid2">Option 2</label>
</div>
</div>
</div>
<p class="control-item-error-message" id="radioLayoutRowInvalidErrorText">Please make a choice.</p>
</fieldset> Fieldset <legend>
For accessibility reasons, it is required to provide understandable radio button labels without relying on visual context. It is also good practice to add a radio button group title inside a <legend> element as the first child of the <fieldset> element. Screen readers will read the legend before navigating through the radio buttons; this way, keyboard navigation users have more information on what is expected with the multiple radio buttons element.
<div class="row">
<fieldset class="col-md-6">
<legend>Radio buttons group example</legend>
<div class="radio-button-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioGroup1" name="radioGroup" aria-describedby="radioGroup1ExtraLabel radioGroup1Description" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioGroup1">Group radio button 1</label>
<p class="radio-button-extra-label" id="radioGroup1ExtraLabel">Extra label</p>
<p class="control-item-description" id="radioGroup1Description">Description text</p>
</div>
<div class="control-item-assets-container">
<svg width="1rem" height="1rem" fill="currentColor" aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</div>
<div class="radio-button-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="radio" value="" id="radioGroup2" name="radioGroup" aria-describedby="radioGroup2ExtraLabel radioGroup2Description" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="radioGroup2">Group radio button 2</label>
<p class="radio-button-extra-label" id="radioGroup2ExtraLabel">Extra label</p>
<p class="control-item-description" id="radioGroup2Description">Description text</p>
</div>
<div class="control-item-assets-container">
<svg width="1rem" height="1rem" fill="currentColor" aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</div>
</fieldset>
</div> Standalone
This standalone version is commonly used for building custom components and should not be used on its own. Remember to provide some sort of accessible name for assistive technologies (for instance, using aria-labelledby, a .visually-hidden, aria-label or a second label). See the forms overview accessibility section for details.
For the standalone radio button, we provide a completely different architecture to ease the integration inside your projects.
<label class="radio-button-standalone">
<input class="control-item-indicator" type="radio" value="" />
<span class="visually-hidden">Default standalone radio button</span>
</label>
Bootstrap
$enable-bootstrap-compatibility: true
This part is enabled only when $enable-bootstrap-compatibility is set to true. Read more
about Bootstrap compatibility.
Be careful when using this, as you must implement the background on hover, focus and active states.
<div>
<input class="form-check-input" type="radio" value="" aria-label="Default standalone radio button (Bootstrap compatible)" />
</div>