Switch
A toggle switch component for boolean states.
Import
ts
import { Description, Label, Switch, SwitchGroup } from '@heroui-vue/vue'Usage
Basic
<template>
<Switch>
<Label class="text-sm">Enable notifications</Label>
</Switch>
</template>
<script setup>
import { Switch, Label } from '@heroui-vue/vue'
</script>Anatomy
vue
<template>
<Switch>
<span data-slot="switch-control">
<span data-slot="switch-thumb">
<span data-slot="switch-icon" />
</span>
</span>
<div data-slot="switch-content">
<Label />
<Description />
</div>
</Switch>
</template>Disabled
<template>
<Switch is-disabled>
<Label class="text-sm">Enable notifications</Label>
</Switch>
</template>
<script setup>
import { Label, Switch } from '@heroui-vue/vue'
</script>Default Selected
<template>
<Switch default-selected>
<Label class="text-sm">Enable notifications</Label>
</Switch>
</template>
<script setup>
import { Label, Switch } from '@heroui-vue/vue'
</script>Controlled
Switch is off
<template>
<div class="flex flex-col gap-4">
<Switch v-model="isSelected">
<Label class="text-sm">Enable notifications</Label>
</Switch>
<p class="m-0 text-sm text-muted">Switch is {{ isSelected ? 'on' : 'off' }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Label, Switch } from '@heroui-vue/vue'
const isSelected = ref(false)
</script>Without Label
<template>
<Switch aria-label="Enable notifications" />
</template>
<script setup>
import { Switch } from '@heroui-vue/vue'
</script>Sizes
<template>
<div class="flex gap-6">
<Switch size="sm">
<Label class="text-xs">Small</Label>
</Switch>
<Switch size="md">
<Label class="text-sm">Medium</Label>
</Switch>
<Switch size="lg">
<Label class="text-base">Large</Label>
</Switch>
</div>
</template>
<script setup>
import { Label, Switch } from '@heroui-vue/vue'
</script>Label Position
<template>
<div class="flex flex-col gap-4">
<Switch>
<Label class="text-sm">Label after</Label>
</Switch>
<Switch class="flex-row-reverse">
<template #default="{ checked }">
<Label class="text-sm">Label before {{ checked ? 'on' : 'off' }}</Label>
</template>
</Switch>
</div>
</template>
<script setup>
import { Label, Switch } from '@heroui-vue/vue'
</script>With Icons
<template>
<div class="flex flex-wrap justify-center gap-3">
<Switch default-selected size="lg">
<template #icon="{ checked }">
<svg v-if="checked" class="size-3 text-inherit opacity-100" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="m20 6-11 11-5-5" />
</svg>
<svg v-else class="size-3 text-inherit opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2v10" />
<path d="M18.4 6.6a9 9 0 1 1-12.8 0" />
</svg>
</template>
</Switch>
<Switch default-selected size="lg">
<template #icon="{ checked }">
<svg v-if="checked" class="size-3 text-inherit opacity-100" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="4" />
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41" />
</svg>
<svg v-else class="size-3 text-inherit opacity-70" viewBox="0 0 24 24" fill="currentColor">
<path d="M21 14.5A8.5 8.5 0 0 1 9.5 3 9 9 0 1 0 21 14.5Z" />
</svg>
</template>
</Switch>
<Switch default-selected size="lg" style="--switch-control-bg-checked: rgb(239 68 68 / 80%); --switch-control-bg-checked-hover: rgb(220 38 38 / 85%);">
<template #icon="{ checked }">
<svg v-if="checked" class="size-3 text-inherit opacity-100" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 3l18 18" />
<path d="M9 9v3a3 3 0 0 0 5.1 2.1" />
<path d="M15 9.3V5a3 3 0 0 0-5.6-1.5" />
<path d="M19 10v2a7 7 0 0 1-.8 3.3" />
<path d="M5 10v2a7 7 0 0 0 10.5 6.1" />
</svg>
<svg v-else class="size-3 text-inherit opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" />
<path d="M19 10v2a7 7 0 0 1-14 0v-2" />
<path d="M12 19v3" />
</svg>
</template>
</Switch>
<Switch default-selected size="lg" style="--switch-control-bg-checked: rgb(168 85 247 / 80%); --switch-control-bg-checked-hover: rgb(147 51 234 / 85%);">
<template #icon="{ checked }">
<svg v-if="checked" class="size-3 text-inherit opacity-100" viewBox="0 0 24 24" fill="currentColor">
<path d="M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9Z" />
<path d="M10 21h4" />
</svg>
<svg v-else class="size-3 text-inherit opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="m2 2 20 20" />
<path d="M8.7 4.7A6 6 0 0 1 18 8c0 7 3 7 3 9H11" />
<path d="M6 8c0 2.2-.3 3.7-.8 4.8" />
<path d="M10 21h4" />
</svg>
</template>
</Switch>
<Switch default-selected size="lg" style="--switch-control-bg-checked: rgb(59 130 246 / 80%); --switch-control-bg-checked-hover: rgb(37 99 235 / 85%);">
<template #icon="{ checked }">
<svg v-if="checked" class="size-3 text-inherit opacity-100" viewBox="0 0 24 24" fill="currentColor">
<path d="M11 5 6 9H2v6h4l5 4V5Z" />
<path d="M15.5 8.5a5 5 0 0 1 0 7" />
<path d="M18.5 5.5a9 9 0 0 1 0 13" />
</svg>
<svg v-else class="size-3 text-inherit opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M11 5 6 9H2v6h4l5 4V5Z" />
<path d="m22 9-6 6" />
<path d="m16 9 6 6" />
</svg>
</template>
</Switch>
</div>
</template>
<script setup>
import { Switch } from '@heroui-vue/vue'
</script>With Description
<template>
<div class="max-w-sm text-left">
<Switch>
<Label class="text-sm">Public profile</Label>
<Description>
Allow others to see your profile information, recent activity, and public workspace
membership across shared project pages.
</Description>
</Switch>
</div>
</template>
<script setup>
import { Description, Label, Switch } from '@heroui-vue/vue'
</script>Group
<template>
<SwitchGroup>
<Switch name="notifications">
<Label class="text-sm">Allow Notifications</Label>
</Switch>
<Switch name="marketing">
<Label class="text-sm">Marketing emails</Label>
</Switch>
<Switch name="social">
<Label class="text-sm">Social media updates</Label>
</Switch>
</SwitchGroup>
</template>
<script setup>
import { Label, Switch, SwitchGroup } from '@heroui-vue/vue'
</script>Group Horizontal
<template>
<SwitchGroup class="overflow-x-auto" orientation="horizontal">
<Switch name="notifications">
<Label class="text-sm">Notifications</Label>
</Switch>
<Switch name="marketing">
<Label class="text-sm">Marketing</Label>
</Switch>
<Switch name="social">
<Label class="text-sm">Social</Label>
</Switch>
</SwitchGroup>
</template>
<script setup>
import { Label, Switch, SwitchGroup } from '@heroui-vue/vue'
</script>Custom Styles
<template>
<Switch
default-selected
style="--switch-control-bg: rgb(203 213 225); --switch-control-bg-hover: rgb(148 163 184); --switch-control-bg-checked: rgb(6 182 212); --switch-control-bg-checked-hover: rgb(8 145 178);"
>
<template #icon="{ checked }">
<svg v-if="checked" class="size-3 text-inherit" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="m20 6-11 11-5-5" />
</svg>
<svg v-else class="size-3 text-inherit opacity-70" viewBox="0 0 24 24" fill="currentColor">
<path d="M21 14.5A8.5 8.5 0 0 1 9.5 3 9 9 0 1 0 21 14.5Z" />
</svg>
</template>
<Label class="text-sm">Custom switch</Label>
</Switch>
</template>
<script setup>
import { Label, Switch } from '@heroui-vue/vue'
</script>Styling
CSS Classes
| Class | Description |
|---|---|
.switch | Base switch wrapper |
.switch__control | Track element |
.switch__thumb | Thumb element |
.switch__icon | Optional thumb icon |
.switch__content | Label/description wrapper |
.switch--sm | Small size |
.switch--md | Medium size |
.switch--lg | Large size |
.switch-group | Group wrapper |
.switch-group__items | Group item layout wrapper |
.switch-group--horizontal | Horizontal group orientation |
.switch-group--vertical | Vertical group orientation |
Interactive States
| State | Selector |
|---|---|
| Selected | [aria-checked="true"] / [data-selected="true"] |
| Hover | [data-hovered="true"] |
| Pressed | [data-pressed="true"] |
| Focus visible | [data-focus-visible="true"] |
| Disabled | [aria-disabled="true"] / [data-disabled="true"] |
| Invalid | [data-invalid="true"] |
| Required | [data-required="true"] |
API
Switch Props
| Prop | Type | Default | Description |
|---|---|---|---|
v-model | boolean | undefined | Controlled selected state |
checked | boolean | undefined | Controlled selected state alias |
isSelected | boolean | undefined | React-style controlled selected alias |
defaultChecked | boolean | false | Initial selected state |
defaultSelected | boolean | undefined | React-style initial selected alias |
size | 'sm' | 'md' | 'lg' | 'md' | Switch size |
disabled | boolean | undefined | Disable the switch |
isDisabled | boolean | undefined | React-style disabled alias |
isInvalid | boolean | undefined | Invalid state |
required | boolean | undefined | Native required state |
isRequired | boolean | undefined | React-style required alias |
name | string | undefined | Form name |
value | string | undefined | Form value |
Switch Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | boolean | Emitted when selected state changes |
update:checked | boolean | Emitted when selected state changes |
change | boolean | Emitted when selected state changes |
Switch Slots
| Slot | Props | Description |
|---|---|---|
default | { checked, isSelected } | Label and description content |
icon | { checked, isSelected } | Optional thumb icon |
SwitchGroup Props
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | 'horizontal' | 'vertical' | undefined | Group orientation |