Switch
Create consistent cross-browser and cross-device switches.
On this page
- Switch v1.5.0
You can find here the OUDS Switch design guidelines.
Overview
Switches allow users to turn an individual option on or off. They are usually used to activate or deactivate a specific setting.
They are implemented using .switch-item and .control-item-* classes, see below. Browser default checkboxes are replaced with the help of .control-item-indicator[role="switch"].
<ul class="control-items-list">
<li class="switch-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchDefault" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchDefault">Default switch</label>
</div>
</li>
<li class="switch-item">
<div class="control-item-assets-container">
<input checked class="control-item-indicator" type="checkbox" role="switch" value="" id="switchDefault2" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchDefault2">Checked switch</label>
</div>
</li>
</ul>
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 form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="switchCheckDefault" />
<label class="form-check-label" for="switchCheckDefault">Default switch (Bootstrap compatible)</label>
</div>
<div class="form-check form-switch">
<input checked class="form-check-input" type="checkbox" role="switch" id="switchCheckChecked" />
<label class="form-check-label" for="switchCheckChecked">Checked switch (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.
Switch grouping and error handling
As switch items can be used inside a list or a form, but also in a standalone way, there are several ways to group them. You can use a <fieldset> container if they are in a form, with an optional <legend> (read more here), you can also use a <ul> (like most of the examples in this page). For both these solutions please add a .control-items-list class on the list container.
For automatic error handling on a single switch, you need to surround it in a .switch-item-container, read more in the invalid state section.
Variants
Divider
To display a divider, add .control-item-divider to a .switch-item.
<ul class="control-items-list">
<li class="switch-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchDivider" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchDivider">Default switch with divider</label>
</div>
</li>
<li class="switch-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchDivider2" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchDivider2">Checked switch with divider</label>
</div>
</li>
</ul> 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 .switch-item.
The .control-item-assets-container containing the icon must be the last child of the .switch-item, as the flow of the item is reversed by CSS to work like other control items.
<ul class="control-items-list">
<li class="switch-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchWithSVG" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchWithSVG">Default switch with an SVG icon</label>
</div>
<div class="control-item-assets-container">
<svg aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</li>
<li class="switch-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchWithIconFont" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchWithIconFont">Checked switch with a font-icon</label>
</div>
<div class="control-item-assets-container">
<span class="icon si si-settings" aria-hidden="true"></span>
</div>
</li>
</ul> 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.
-
Description text
-
Description text
<ul class="control-items-list">
<li class="switch-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" aria-describedby="switchDescription" id="switchWithDescription" value="" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchWithDescription">Default switch</label>
<p class="control-item-description" id="switchDescription">Description text</p>
</div>
</li>
<li class="switch-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" aria-describedby="switchDescription2" id="switchWithDescription2" value="" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchWithDescription2">Checked switch</label>
<p class="control-item-description" id="switchDescription2">Description text</p>
</div>
</li>
</ul> Layout
Default
It's recommended to keep switch label to no more than three words. When space is limited or when a long label or description text is required, the text can wrap, as this is preferable to truncation. The switch indicator and the icon will remain vertically centered, until the .control-item-assets-container reaches a defined maximum height.
-
Description text
-
Also a longer description text, it will also wrap at some point depending on the component width
<div class="row">
<div class="col-8 col-md-6 col-xl-5">
<ul class="control-items-list">
<li class="switch-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchLayout1" aria-describedby="switchLayout1Description" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchLayout1">Label</label>
<p class="control-item-description" id="switchLayout1Description">Description text</p>
</div>
<div class="control-item-assets-container">
<svg aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</li>
<li class="switch-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchLayout2" checked aria-describedby="switchLayout2Description" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchLayout2">A longer label for showing behavior in this case, switch indicator and icon will stick to the top area of the component</label>
<p class="control-item-description" id="switchLayout2Description">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 aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</li>
</ul>
</div>
</div> Reverse
To reverse the component, simply add .control-item-reverse to a .switch-item.
-
Description text
-
Also a longer description text, it will also wrap at some point depending on the component width
<div class="row">
<div class="col-8 col-md-6 col-xl-5">
<ul class="control-items-list">
<li class="switch-item control-item-divider control-item-reverse">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchLayoutRev1" aria-describedby="switchLayoutRev1Description" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchLayoutRev1">Label with reverse layout</label>
<p class="control-item-description" id="switchLayoutRev1Description">Description text</p>
</div>
<div class="control-item-assets-container">
<svg aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</li>
<li class="switch-item control-item-divider control-item-reverse">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchLayoutRev2" checked aria-describedby="switchLayoutRev2Description" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchLayoutRev2">A longer label with reverse layout for showing behavior in this case, switch indicator and icon will stick to the top area of the component</label>
<p class="control-item-description" id="switchLayoutRev2Description">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 aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</li>
</ul>
</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 switches on the opposite side with the .form-check-reverse modifier class.
<div class="form-check form-switch form-check-reverse">
<input class="form-check-input" type="checkbox" role="switch" id="switchCheckReverse" checked />
<label class="form-check-label" for="switchCheckReverse">Reverse switch (Bootstrap compatible)</label>
</div> States
Disabled
Add the disabled attribute to the input, then the switch and the associated <label> are automatically styled to match with a lighter color to help indicate the input’s state.
<ul class="control-items-list">
<li class="switch-item">
<div class="control-item-assets-container">
<input disabled class="control-item-indicator" type="checkbox" role="switch" value="" id="switchDisabled" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchDisabled">Default disabled switch</label>
</div>
</li>
<li class="switch-item">
<div class="control-item-assets-container">
<input disabled class="control-item-indicator" type="checkbox" role="switch" value="" id="switchCheckedDisabled" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchCheckedDisabled">Checked disabled switch</label>
</div>
</li>
</ul>
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 form-switch">
<input disabled class="form-check-input" type="checkbox" role="switch" id="switchCheckDisabled" />
<label class="form-check-label" for="switchCheckDisabled">Default disabled checkbox (Bootstrap compatible)</label>
</div>
<div class="form-check form-switch">
<input disabled class="form-check-input" type="checkbox" role="switch" id="switchCheckCheckedDisabled" checked />
<label class="form-check-label" for="switchCheckCheckedDisabled">Checked disabled switch (Bootstrap compatible)</label>
</div> Read only
To create a read only switch, the input should be replaced by a span element with role="switch", aria-readonly="true" and aria-disabled="true" attributes. The switch will be accessible to keyboard navigation and assistive technologies thanks to aria-labelledby and tabindex, but other interactions will be prevented.
-
Default readonly switch
-
Checked readonly switch
<ul class="control-items-list">
<li class="switch-item">
<div class="control-item-assets-container">
<span class="control-item-indicator" role="switch" aria-readonly="true" aria-disabled="true" tabindex="0" aria-checked="false" aria-labelledby="switchReadonlyLabel"></span>
</div>
<div class="control-item-text-container">
<p class="control-item-label" id="switchReadonlyLabel">Default readonly switch</p>
</div>
</li>
<li class="switch-item">
<div class="control-item-assets-container">
<span class="control-item-indicator" role="switch" aria-readonly="true" aria-disabled="true" tabindex="0" aria-checked="true" aria-labelledby="switchReadonlyCheckedLabel"></span>
</div>
<div class="control-item-text-container">
<p class="control-item-label" id="switchReadonlyCheckedLabel">Checked readonly switch</p>
</div>
</li>
</ul> Invalid
The invalid state is the equivalent of the ‘Error’ state that you can find in the design specification.
To display an invalid switch, add .is-invalid to a .control-item-indicator. Please take a look at our Validation page to learn more.
Error text on one switch item
To automatically display an error text on a single switch item, enclose it inside a .switch-item-container and add a .control-item-error-message as a sibling of the .switch-item.
Description text
<div class="switch-item-container">
<div class="switch-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator is-invalid" type="checkbox" role="switch" value="" id="switchInvalid" aria-describedby="switchInvalidDescription switchInvalidErrorText" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchInvalid">Default invalid switch</label>
<p class="control-item-description" id="switchInvalidDescription">Description text</p>
</div>
</div>
<p class="control-item-error-message" id="switchInvalidErrorText">Cannot be activated at this time.</p>
</div>
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 switch, add .is-invalid to a .form-check-input.
<div class="form-check form-switch">
<input class="form-check-input is-invalid" type="checkbox" value="" id="checkInvalid" role="switch" />
<label class="form-check-label" for="checkInvalid">
Default invalid switch (Bootstrap compatible)
</label>
</div> To add an error message on a single switch item inside a list, the .switch-item should be inside a <li> with a .switch-item-container class. The error text will only be displayed when this particular switch's .control-item-indicator is invalid.
-
Description text
-
Description text
<ul class="list-unstyled">
<li class="switch-item-container">
<div class="switch-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator is-invalid" type="checkbox" role="switch" value="" id="switchInvalidUl" aria-describedby="switchInvalidUlDescription switchInvalidErrorTextUl" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchInvalidUl">Default invalid switch</label>
<p class="control-item-description" id="switchInvalidUlDescription">Description text</p>
</div>
</div>
<p class="control-item-error-message mb-xsmall" id="switchInvalidErrorTextUl">Cannot be activated at this time.</p>
</li>
<li class="switch-item-container">
<div class="switch-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchInvalidUl2" aria-describedby="switchInvalidUl2Description switchInvalidErrorTextUl2" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchInvalidUl2">Default invalid switch</label>
<p class="control-item-description" id="switchInvalidUl2Description">Description text</p>
</div>
</div>
<p class="control-item-error-message" id="switchInvalidErrorTextUl2">Cannot be activated at this time.</p>
</li>
</ul> Error text on a group
If the switch items list is part of a form, add a <fieldset> with the class .control-items-list, the error text will be automatically displayed if any of the .control-item-indicators inside the <fieldset> is invalid.
<fieldset class="control-items-list">
<div class="switch-item">
<div class="control-item-assets-container">
<input class="control-item-indicator is-invalid" type="checkbox" role="switch" value="" id="switchInvalidFieldset" aria-describedby="switchInvalidFieldsetDescription switchInvalidErrorTextGroup" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchInvalidFieldset">Default invalid switch</label>
<p class="control-item-description" id="switchInvalidFieldsetDescription">Description text</p>
</div>
</div>
<div class="switch-item">
<div class="control-item-assets-container">
<input class="control-item-indicator is-invalid" type="checkbox" role="switch" value="" id="switchInvalidFieldset2" aria-describedby="switchInvalidFieldset2Description switchInvalidErrorTextGroup" checked />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchInvalidFieldset2">Checked invalid switch</label>
<p class="control-item-description" id="switchInvalidFieldset2Description">Description text</p>
</div>
</div>
<p class="control-item-error-message" id="switchInvalidErrorTextGroup">Incompatible choices.</p>
</fieldset> Fieldset <legend>
For accessibility reasons, it is required to provide understandable switch labels without relying on visual context. If switches belong to a group, it is good practice to add a group title inside a <legend> element as the first child of the <fieldset> element. Screen readers will read the legend before navigating through the switches; this way, keyboard navigation users have more information on what is expected with the multiple switches element.
<div class="row">
<div class="col-md-6">
<fieldset class="control-items-list">
<legend>Switches group example</legend>
<div class="switch-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchGroup1" aria-describedby="switchGroup1Description" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchGroup1">Group switch 1</label>
<p class="control-item-description" id="switchGroup1Description">Description text</p>
</div>
<div class="control-item-assets-container">
<svg aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</div>
<div class="switch-item control-item-divider">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchGroup2" checked aria-describedby="switchGroup2Description" />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchGroup2">Group switch 2</label>
<p class="control-item-description" id="switchGroup2Description">Description text</p>
</div>
<div class="control-item-assets-container">
<svg aria-hidden="true">
<use xlink:href="/orange/docs/0.6/assets/img/ouds-web-sprite.svg#heart-empty" />
</svg>
</div>
</div>
</fieldset>
</div>
</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 switch, we provide a completely different architecture to ease the integration inside your projects.
<label class="switch-standalone">
<input class="control-item-indicator" type="checkbox" role="switch" value="" />
<span class="visually-hidden">Standalone switch</span>
</label> Native switches
Progressively enhance your switches for mobile Safari (iOS 17.4+) by adding a switch attribute to your input to enable haptic feedback when toggling switches, just like native iOS switches. There are no style changes attached to using this attribute in OUDS Web as all our switches use custom styles.
<div class="switch-item">
<div class="control-item-assets-container">
<input class="control-item-indicator" type="checkbox" role="switch" value="" id="switchNative" switch />
</div>
<div class="control-item-text-container">
<label class="control-item-label" for="switchNative">Native switch haptics</label>
</div>
</div> Be sure to read more about the switch attribute on the WebKit blog. Safari 17.4+ on macOS and iOS both have native-style switches in HTML while other browsers simply fall back to the standard checkbox appearance. Applying the attribute to a non-OUDS Web checkbox in more recent versions of Safari will render a native switch.