Switch
A control element that allows for a binary selection.
Anatomy
To set up the switch correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-part
attribute to help identify them in the DOM.
Design impact on the asChild property
The Switch.Root
element of the switch is a label
element. This is because the switch is a form
control and should be associated with a label to provide context and meaning to the user. Otherwise,
the HTML and accessibility structure will be invalid.
If you need to use the
asChild
property, make sure that thelabel
element is the direct child of theSwitch.Root
component.
Examples
Learn how to use the Switch
component in your project. Let's take a look at the most basic
example:
import { Switch } from '@ark-ui/react/switch'
export const Basic = () => (
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Label>Label</Switch.Label>
<Switch.HiddenInput />
</Switch.Root>
)
import { Switch } from '@ark-ui/solid/switch'
export const Basic = () => (
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Label>Label</Switch.Label>
<Switch.HiddenInput />
</Switch.Root>
)
<script setup lang="ts">
import { Switch } from '@ark-ui/vue/switch'
</script>
<template>
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Label>Label</Switch.Label>
<Switch.HiddenInput />
</Switch.Root>
</template>
Controlled Switch
For a controlled Switch component, the state of the toggle is managed using the checked prop, and
updates when the onCheckedChange
event handler is called:
import { Switch } from '@ark-ui/react/switch'
import { useState } from 'react'
export const Controlled = () => {
const [checked, setChecked] = useState(false)
return (
<Switch.Root checked={checked} onCheckedChange={(e) => setChecked(e.checked)}>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Label>Label</Switch.Label>
<Switch.HiddenInput />
</Switch.Root>
)
}
import { Switch } from '@ark-ui/solid/switch'
import { createSignal } from 'solid-js'
export const Controlled = () => {
const [checked, setChecked] = createSignal(false)
return (
<Switch.Root checked={checked()} onCheckedChange={(e) => setChecked(e.checked)}>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Label>Label</Switch.Label>
<Switch.HiddenInput />
</Switch.Root>
)
}
<script setup lang="ts">
import { Switch } from '@ark-ui/vue/switch'
import { ref } from 'vue'
const checked = ref(true)
</script>
<template>
<Switch.Root v-model:checked="checked">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Label>Label</Switch.Label>
<Switch.HiddenInput />
</Switch.Root>
</template>
Render Prop Usage
The Switch component also allows for a render prop, granting direct access to its internal state. This enables you to dynamically adjust and customize aspects of the component based on its current state:
import { Switch } from '@ark-ui/react/switch'
export const RenderProp = () => (
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Context>
{(context) => (
<Switch.Label>Feature is {context.checked ? 'enabled' : 'disabled'}</Switch.Label>
)}
</Switch.Context>
<Switch.HiddenInput />
</Switch.Root>
)
import { Switch } from '@ark-ui/solid/switch'
export const RenderProp = () => (
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Context>
{(context) => (
<Switch.Label>Feature is {context().checked ? 'enabled' : 'disabled'}</Switch.Label>
)}
</Switch.Context>
<Switch.HiddenInput />
</Switch.Root>
)
<script setup lang="ts">
import { Switch } from '@ark-ui/vue/switch'
</script>
<template>
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Context v-slot="api">
<Switch.Label>Feature is {{ api.checked ? 'enabled' : 'disabled' }}</Switch.Label>
</Switch.Context>
<Switch.HiddenInput />
</Switch.Root>
</template>
Using the Field Component
The Field
component helps manage form-related state and accessibility attributes of a switch.
It includes handling ARIA labels, helper text, and error text to ensure proper accessibility.
import { Field } from '@ark-ui/react/field'
import { Switch } from '@ark-ui/react/switch'
export const WithField = (props: Field.RootProps) => (
<Field.Root {...props}>
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Label>Label</Switch.Label>
<Switch.HiddenInput />
</Switch.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
)
import { Field } from '@ark-ui/solid/field'
import { Switch } from '@ark-ui/solid/switch'
export const WithField = (props: Field.RootProps) => (
<Field.Root {...props}>
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Label>Label</Switch.Label>
<Switch.HiddenInput />
</Switch.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
)
<script setup lang="ts">
import { Field } from '@ark-ui/vue/field'
import { Switch } from '@ark-ui/vue/switch'
</script>
<template>
<Field.Root>
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Label>Label</Switch.Label>
<Switch.HiddenInput />
</Switch.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
</template>
Using the Root Provider
The RootProvider
component provides a context for the switch. It accepts the value of the useSwitch
hook.
You can leverage it to access the component state and methods from outside the switch.
import { Switch, useSwitch } from '@ark-ui/react/switch'
export const RootProvider = () => {
const switchApi = useSwitch()
return (
<>
<button onClick={() => switchApi.toggleChecked()}>Toggle</button>
<Switch.RootProvider value={switchApi}>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Label>Label</Switch.Label>
<Switch.HiddenInput />
</Switch.RootProvider>
</>
)
}
import { Switch, useSwitch } from '@ark-ui/solid/switch'
export const RootProvider = () => {
const switchApi = useSwitch()
return (
<>
<button onClick={() => switchApi().toggleChecked()}>Toggle</button>
<Switch.RootProvider value={switchApi}>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Label>Label</Switch.Label>
<Switch.HiddenInput />
</Switch.RootProvider>
</>
)
}
<script setup lang="ts">
import { Switch, useSwitch } from '@ark-ui/vue/switch'
const switchApi = useSwitch()
</script>
<template>
<button @click="switchApi.toggleChecked()">Toggle</button>
<Switch.RootProvider :value="switchApi">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Label>Label</Switch.Label>
<Switch.HiddenInput />
</Switch.RootProvider>
</template>
If you're using the
RootProvider
component, you don't need to use theRoot
component.
API Reference
Root
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'label'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
checked | boolean Whether the switch is checked. | |
defaultChecked | boolean The checked state of the switch when it is first rendered. Use this when you do not need to control the state of the switch. | |
disabled | boolean Whether the switch is disabled. | |
ids | Partial<{
root: string
hiddenInput: string
control: string
label: string
thumb: string
}> The ids of the elements in the switch. Useful for composition. | |
invalid | boolean If `true`, the switch is marked as invalid. | |
label | string Specifies the localized strings that identifies the accessibility elements and their states | |
name | string The name of the input field in a switch (Useful for form submission). | |
onCheckedChange | (details: CheckedChangeDetails) => void Function to call when the switch is clicked. | |
readOnly | boolean Whether the switch is read-only | |
required | boolean If `true`, the switch input is marked as required, | |
value | 'on' | string | number The value of switch input. Useful for form submission. |
Data Attribute | Value |
---|---|
[data-active] | Present when active or pressed |
[data-focus] | Present when focused |
[data-focus-visible] | Present when focused with keyboard |
[data-readonly] | Present when read-only |
[data-hover] | Present when hovered |
[data-disabled] | Present when disabled |
[data-state] | "checked" | "unchecked" |
[data-invalid] | Present when invalid |
Control
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'span'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-active] | Present when active or pressed |
[data-focus] | Present when focused |
[data-focus-visible] | Present when focused with keyboard |
[data-readonly] | Present when read-only |
[data-hover] | Present when hovered |
[data-disabled] | Present when disabled |
[data-state] | "checked" | "unchecked" |
[data-invalid] | Present when invalid |
HiddenInput
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'input'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Label
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'span'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-active] | Present when active or pressed |
[data-focus] | Present when focused |
[data-focus-visible] | Present when focused with keyboard |
[data-readonly] | Present when read-only |
[data-hover] | Present when hovered |
[data-disabled] | Present when disabled |
[data-state] | "checked" | "unchecked" |
[data-invalid] | Present when invalid |
RootProvider
Prop | Default | Type |
---|---|---|
value | UseSwitchReturn | |
asChild | (props: ParentProps<'label'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Thumb
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'span'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-active] | Present when active or pressed |
[data-focus] | Present when focused |
[data-focus-visible] | Present when focused with keyboard |
[data-readonly] | Present when read-only |
[data-hover] | Present when hovered |
[data-disabled] | Present when disabled |
[data-state] | "checked" | "unchecked" |
[data-invalid] | Present when invalid |
Accessibility
Complies with the Switch WAI-ARIA design pattern.
Keyboard Support
Key | Description |
---|---|
SpaceEnter | Toggle the switch |