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>
Using with HTML forms
If you add the name
prop to your switch, a hidden input
element will be rendered and kept in sync with the switch state.
<script>
import {
Switch,
SwitchLabel,
SwitchGroup,
} from "@rgossiaux/svelte-headlessui";
let enabled = false;
</script>
<Switch checked={enabled} on:change={(e) => (enabled = e.detail)} name="notifications">
<!-- ... -->
</Switch>
This lets you use a radio group inside a native HTML <form>
and make traditional form submissions as if your radio group was a native HTML form control.
By default, the value will be 'on'
when the switch is checked, and not present when the switch is unchecked.
<input type="hidden" name="notifications" value="on" />
You can customize the value if needed by using the value prop:
<script>
import {
Switch,
SwitchLabel,
SwitchGroup,
} from "@rgossiaux/svelte-headlessui";
let enabled = false;
</script>
<Switch checked={enabled} on:change={(e) => (enabled = e.detail)} name="terms" value="accept">
<!-- ... -->
</Switch>
The hidden input will then use your custom value when the switch is checked:
<input type="hidden" name="terms" value="accept" />
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 |
name |
— | string |
The name used when using this component inside a form. |
value |
— | string |
The value used when using this component inside a form, if it 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 |