Use a Checkbox when the choice is part of a form that requires explicit submission, or when multiple items can be selected at once. Use a Switch when the action takes immediate effect.
When to use
Use a switch when
- Toggling a single setting that takes effect immediately
- The on/off state directly controls a feature, mode, or preference
- The action does not require a separate confirmation or form submission
- You need a compact, recognizable binary control
Do not use a switch when
- The setting only takes effect after the user clicks a Save or Submit button
- Multiple related options need to be selected together (use checkboxes)
- The action is irreversible and needs a confirmation step
- The label text does not clearly describe the result of toggling
Anatomy
inner-label is set to icon, check and X marks appear inside the track to reinforce the on/off state.
| Part | Element | Description |
|---|---|---|
| 1 | Switch toggle | The rounded track and sliding dot that act as the toggle surface |
| 2 | Icon | Optional icon inside the track to reinforce the on/off state (icon mode only) |
| 3 | Label | Optional text describing what the switch controls |
Design guidelines
States
A switch has four interactive states: default (off), checked (on), focused, and disabled. Hover adds a subtle background whenbackground-on-hover is enabled. The disabled state prevents all interaction and dims the control to signal it is unavailable.
Always pair a switch with a visible text label unless the context makes the purpose unmistakably clear (for example, a dark-mode toggle adjacent to sun and moon icons). Unlabeled switches are inaccessible by default.
Inner label
Default (no inner label)
The track contains only the sliding dot. This is the most compact presentation and works well in dense settings panels.
Icon inner label
Set
inner-label="icon" to show a check icon when ON and an X icon when OFF inside the track. This adds a secondary visual reinforcement of the state without relying on color alone.Label position
By default, the label appears to the right of the control. Setreverse-order to move it to the left — useful in right-to-left layouts or when a consistent label-first alignment is required across a settings list.
Usage
Default
The default switch provides a basic on/off toggle functionality, allowing users to control a binary state effortlessly.Checked
Use thechecked attribute to set the initial state of the toggle as ON. This is ideal when you want the switch to start in an activated position.
Options
Disabled
The disabled switch prevents user interaction, making it visually clear that the toggle functionality is not currently available or applicable. Use thedisabled attribute to enable this type of switch.
With inner label
Enhance user understanding by incorporating an inner label that provides context about the current state of the switch. Use theinner-label="icon" attribute to activate this variant.
Reverse order
The reverse order switch alters the visual arrangement, placing the toggle on the opposite side for a customizable user interface by adding thereverse-order attribute.
Full width
Usefull-width with reverse-order and justify-content="space-between" to build standard settings-list rows where the label is on the left and the toggle sits flush to the right edge.
Best practices
DoUse concise, present-tense labels that clearly describe the result of the switch being on. “Enable notifications” or “Dark mode” communicate the outcome at a glance.
Don’tUse vague labels like “Toggle” or “On/Off”. Users should not need to think about what the switch controls — the label must describe the setting itself.
DoApply the switch’s effect immediately without requiring a submit action. Use this pattern for preferences that take effect in real time — dark mode, notifications, or feature flags.
Don’tUse a switch when the change only takes effect after the user clicks a Save button. If the state is not immediately applied, use a checkbox inside a form instead.
DoUse
inner-label="icon" to supplement the color change with a shape cue (check / X). This improves the control for users with color vision deficiencies who cannot rely on brand color alone.Don’tRely solely on the track color to communicate the ON state. Always ensure that at least one additional cue — dot position or icon — distinguishes the two states.
DoPlace the label directly adjacent to the switch and keep the pairing stable across the list. Consistent label position helps users scan a settings panel without searching for the control.
Don’tChange the label text based on state (for example, “Enabled” when on and “Disabled” when off). The label should always describe the setting — the control itself communicates the current state.
Accessibility
bq-switch renders a native <input type="checkbox" role="switch"> inside its shadow DOM, which ensures that assistive technologies correctly announce the control as a switch with an on/off state.
Keyboard interaction
| Key | Action |
|---|---|
Tab | Moves focus to the switch |
Space | Toggles the switch on or off |
Developer responsibilities
- Always provide a visible text label via the default slot. The switch derives its accessible name from the
nameprop viaaria-labelon the native<input>— the visible slot text is not automatically wired to the control. If you want the visible label to serve as the accessible name, usearia-labelledbyon the host element pointing to the associated label element. - Use the
nameattribute (required) to participate in form submissions and to give the control a machine-readable identifier. - When the switch is
disabled, it is excluded from the tab order and will not respond to keyboard or pointer events. Make sure the reason for disabling is communicated through surrounding text. - The
bqChangeevent is cancelable. Callingevent.preventDefault()inside abqChangehandler prevents the switch from updating its visual state, which is useful when you need to confirm a change before applying it. - Use
vFocus(),vBlur(), andvClick()instead of the globalelement.focus(),element.blur(), andelement.click()to interact with the native input correctly across Shadow DOM boundaries.
API reference
Properties
| Property | Attribute | Description | Type | Default |
|---|---|---|---|---|
backgroundOnHover | background-on-hover | If true, a background is shown on hover | boolean | false |
checked | checked | If true, the switch starts in the ON state | boolean | false |
disabled | disabled | If true, the switch is disabled and non-interactive | boolean | false |
formValidationMessage | form-validation-message | Custom native form validation message | string | — |
fullWidth | full-width | If true, the switch expands to fill its container | boolean | false |
innerLabel | inner-label | How to display the on/off marks inside the control | 'default' | 'icon' | 'default' |
justifyContent | justify-content | Space distribution between the control and label; accepts any justify-content value | 'start' | 'end' | 'center' | 'flex-start' | 'flex-end' | 'left' | 'right' | 'space-between' | 'space-around' | 'space-evenly' | 'stretch' | 'normal' | 'inherit' | 'initial' | 'start' |
name | name | Form control name; submitted as part of a name/value pair | string | required |
required | required | If true, the switch must be ON before the form can be submitted | boolean | false |
reverseOrder | reverse-order | If true, the label appears before the control | boolean | false |
value | value | Sets the underlying <input> value attribute. Note: the form submission value is the fixed string 'on' when checked (via ElementInternals), regardless of this prop | string | — |
Methods
| Method | Description | Signature |
|---|---|---|
vBlur() | Removes focus from the native <input> element | Promise<void> |
vClick() | Simulates a click on the native <input> element | Promise<void> |
vFocus() | Sets focus on the native <input> element | Promise<void> |
Events
| Event | Description | Type |
|---|---|---|
bqBlur | Emitted when the switch loses focus | CustomEvent<HTMLBqSwitchElement> |
bqChange | Emitted when the switch state changes; cancelable via event.preventDefault() | CustomEvent<{ checked: boolean }> |
bqFocus | Emitted when the switch gains focus | CustomEvent<HTMLBqSwitchElement> |
Slots
| Slot | Description |
|---|---|
| (default) | The label text displayed next to the control |
icon-on | Custom icon shown inside the track when the switch is ON (requires inner-label="icon") |
icon-off | Custom icon shown inside the track when the switch is OFF (requires inner-label="icon") |
Shadow parts
| Part | Description |
|---|---|
base | The <label> root container element |
control | The <div> element that forms the toggle track |
dot | The <div> element that acts as the sliding indicator dot |
icon-on | The <bq-icon> element used as the ON mark (icon mode only) |
icon-off | The <bq-icon> element used as the OFF mark (icon mode only) |
label | The <span> element that holds the label text |
CSS custom properties
| Variable | Description | Default |
|---|---|---|
--bq-switch--height | Height of the switch track | 24px |
--bq-switch--width | Width of the switch track | 44px |
--bq-switch--dot-size | Diameter of the sliding dot | calc(var(--bq-switch--height) - (var(--bq-spacing-xs2) * 2)) |
--bq-switch--justify-content | Space distribution between the control and label | start |
Resources
Interactive playground
Explore switch variants and states in Storybook
Source code
View the component source on GitHub