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
bind:checked={enabled}
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
bind:checked={enabled}
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 bind:checked={enabled}>
<!-- ... -->
</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 bind:checked={enabled}>
<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 |
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 |