Switch
Basic example
Switches are built using the Switch component. You can toggle your switch by clicking directly on the component or by pressing the spacebar while it’s focused.
Toggling the switch fires the change event with a negated version of the checked value.
<script>
import { Switch } from "@rgossiaux/svelte-headlessui";
let enabled = false;
</script>
<Switch
checked={enabled}
on:change={(e) => (enabled = e.detail)}
class={enabled ? "switch switch-enabled" : "switch switch-disabled"}
>
<span class="sr-only">Enable notifications</span>
<span class="toggle" class:toggle-on={enabled} class:toggle-off={!enabled} />
</Switch>
<style>
:global(.switch) {
position: relative;
display: inline-flex;
align-items: center;
border-radius: 9999px;
height: 1.5rem;
width: 2.75rem;
}
:global(.switch-enabled) {
/* Blue */
background-color: rgb(37 99 235);
}
:global(.switch-disabled) {
/* Gray */
background-color: rgb(229 231 235);
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.toggle {
display: inline-block;
width: 1rem;
height: 1rem;
background-color: rgb(255 255 255);
border-radius: 9999px;
}
.toggle-on {
transform: translateX(1.1rem);
}
.toggle-off {
transform: translateX(-0.25rem);
}
</style>
Styling
See here for some general notes on styling the components in this library.
Using a custom label
By default, the Switch renders a <button> as well as whatever children you pass into it. This can make it harder to implement certain UIs, since the children will be nested within the button.
In these situations, you can use the SwitchGroup component for more flexibility.
This example demonstrates how to use the SwitchGroup, Switch, and SwitchLabel components to render a label as a sibling to a button. Note that SwitchLabel is used alongside a Switch, and both must be rendered within a parent SwitchGroup.
<script>
import {
Switch,
SwitchLabel,
SwitchGroup,
} from "@rgossiaux/svelte-headlessui";
let enabled = false;
</script>
<SwitchGroup>
<div class="switch-container">
<SwitchLabel class="switch-label">Enable notifications</SwitchLabel>
<Switch
checked={enabled}
on:change={(e) => (enabled = e.detail)}
class={enabled ? "switch switch-enabled" : "switch switch-disabled"}
>
<span class="sr-only">Enable notifications</span>
<span
class="toggle"
class:toggle-on={enabled}
class:toggle-off={!enabled}
/>
</Switch>
</div>
</SwitchGroup>
<style>
.switch-container {
display: flex;
align-items: center;
}
:global(.switch-label) {
margin-right: 1rem;
}
:global(.switch) {
position: relative;
display: inline-flex;
align-items: center;
border-radius: 9999px;
height: 1.5rem;
width: 2.75rem;
transition-property: color, background-color, border-color,
text-decoration-color, fill, stroke;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
:global(.switch:focus) {
outline: 2px solid transparent;
outline-offset: 2px;
box-shadow: 0 0 0 2px rgb(99 102 241);
}
:global(.switch-enabled) {
/* Blue */
background-color: rgb(37 99 235);
}
:global(.switch-disabled) {
/* Gray */
background-color: rgb(229 231 235);
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.toggle {
display: inline-block;
width: 1rem;
height: 1rem;
background-color: rgb(255 255 255);
border-radius: 9999px;
transition-property: transform;
}
.toggle-on {
transform: translateX(1.1rem);
}
.toggle-off {
transform: translateX(-0.25rem);
}
</style>
By default, clicking a SwitchLabel will toggle the switch, just like labels in native HTML checkboxes do. If you’d like to make the label non-clickable (which you might if it doesn’t make sense for your design), you can add a passive prop to the SwitchLabel component:
<script>
import {
Switch,
SwitchLabel,
SwitchGroup,
} from "@rgossiaux/svelte-headlessui";
let enabled = false;
</script>
<SwitchGroup>
<SwitchLabel passive>Enable notifications</SwitchLabel>
<Switch checked={enabled} on:change={(e) => (enabled = e.detail)}>
<!-- ... -->
</Switch>
</SwitchGroup>
Transitions
Because switches are always rendered to the DOM (rather than being mounted/unmounted like other components in the library), there’s generally no need to use the provided Transition component. You can just use CSS transitions or Svelte’s transition directives:
<script>
import {
Switch,
SwitchLabel,
SwitchGroup,
} from "@rgossiaux/svelte-headlessui";
let enabled = false;
</script>
<Switch checked={enabled} on:change={(e) => (enabled = e.detail)}>
<span class="toggle" class:enabled>
<!-- ... -->
</span></Switch
>
<style>
.toggle {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
transition-property: transform;
}
.enabled {
transform: translateX(1rem);
}
</style>
Accessibility notes
Labels
By default, the children of a Switch will be used as the label for screen readers. If you’re using SwitchLabel, the content of your Switch component will be ignored by assistive technologies.
Mouse interaction
Clicking a Switch or a SwitchLabel toggles the switch on and off.
Keyboard interaction
When the horizontal prop is set, the <ArrowUp> and <ArrowDown> below become <ArrowLeft> and <ArrowRight>:
| Command | Description |
|---|---|
<Space> when a Switch is focused |
Toggles the switch |
Other
All relevant ARIA attributes are automatically managed.
For a full reference on all accessibility features implemented in Switch, see the ARIA spec on Switch.
Component API
Switch
The main switch component.
| Prop | Default | Type | Description |
|---|---|---|---|
as |
button |
string |
The element the Switch should render as |
checked |
false |
boolean |
Whether the switch is checked |
| Slot prop | Type | Description |
|---|---|---|
checked |
boolean |
Whether the switch is checked |
This component also dispatches a custom event, which is listened to using the Svelte on: directive:
| Event name | Type of event .detail |
Description |
|---|---|---|
change |
T |
Dispatched when a Switch is toggled; the event detail contains the new value of the switch |
SwitchLabel
A label that can be used for more control over the text your switch will announce to screenreaders. Renders an element that is linked to the Switch via the aria-labelledby attribute and an autogenerated id.
| Prop | Default | Type | Description |
|---|---|---|---|
as |
label |
string |
The element the SwitchLabel should render as |
SwitchDescription
This is the description for your switch. When this is used, it will set the aria-describedby on the switch.
| Prop | Default | Type | Description |
|---|---|---|---|
as |
p |
string |
The element the SwitchDescription should render as |
| Slot prop | Type | Description |
|---|---|---|
open |
boolean |
Whether or not the switch is open |
SwitchGroup
Used to wrap a Switch together with a SwitchLabel and/or SwitchDescription
| Prop | Default | Type | Description |
|---|---|---|---|
as |
div |
string |
The element the SwitchGroup should render as |