Switch
A toggle that turns a setting on or off.
<Switch
label="Notifications"
v-model="value"
/>Examples
Notification settings
icon shows an icon before the label.
<script setup lang="ts">
import { Switch } from 'frappe-ui'
</script>
<template>
<div class="flex flex-col gap-3 w-80">
<Switch icon="lucide-bell" label="Notifications" class="w-full" />
<Switch
icon="lucide-mail"
label="Email digest"
description="A weekly summary delivered every Friday."
class="w-full"
/>
</div>
</template>Toolbar toggle
padded gives the switch a clickable surface and a hover state that match the buttons beside it. A click anywhere on the row toggles the switch.
<script setup lang="ts">
import { ref } from 'vue'
import { Button, Switch } from 'frappe-ui'
const showActivity = ref(true)
</script>
<template>
<div class="flex items-center gap-2">
<Switch v-model="showActivity" padded label="Show activity" />
<Button variant="subtle" icon-left="lucide-settings-2" label="Customize" />
<Button variant="solid" icon-right="lucide-chevron-down" label="New" />
</div>
</template>Behavior
Icon
icon takes a lucide- class name, such as "lucide-bell", or a component, which is rendered with <component :is>.
Control position
controlPosition is end by default, so the switch sits after the label and the row fills the available width. start puts the switch before the label, and the row fits its content. Both follow the text direction.
Padded
padded wraps the switch and the label in a clickable surface with hover, active and focus states, for toolbars and menu items. Without padded, only the switch and its label respond to clicks, and the row has no hover or focus state.
Label, description and error
label renders beside the switch and description below it. error renders below the row and hides description. It takes a string, an array of strings (one line each), or an Error, the same values as ErrorMessage. An empty string or an empty array means no error. required adds a red asterisk to the label.
The #label slot replaces the label text and the required marker, and receives { required }. A #description slot is not hidden by error. It renders above the error.
Attributes
class and style go to the layout wrapper. Everything else (name, aria-*, data-* and listeners) goes once to the interactive element, which for Switch is the switch button.
Accessibility
Switch renders a button with role="switch", and Space or Enter toggles it. An icon given as a class name is hidden from screen readers. required sets aria-required. While error is set, the switch gets aria-invalid and an aria-errormessage that points to the error text.
API Reference
Show types
import type { Component } from 'vue'
import type { ToggleSize } from '../../composables/inputTypes'
import type { InputLabelingProps } from '../../composables/useInputLabeling'
export interface SwitchProps extends InputLabelingProps {
/** Size of the switch control */
size?: ToggleSize
/** Wraps the control and label in a clickable surface with hover, active and focus states — useful for settings rows and menu items. */
padded?: boolean
/** Position of the control relative to the label, along the inline axis (RTL-aware). `start` is the leading side, `end` the trailing side. Defaults to `end`, so the switch trails the label. */
controlPosition?: 'start' | 'end'
/** Disables the switch and prevents interaction */
disabled?: boolean
/** Optional icon rendered alongside the label. Strings starting with `lucide-` are rendered via the shared Lucide Tailwind utility; component values are rendered with `<component :is>`. */
icon?: string | Component
}Size of the switch control
Wraps the control and label in a clickable surface with hover, active and focus states — useful for settings rows and menu items.
Position of the control relative to the label, along the inline axis (RTL-aware). `start` is the leading side, `end` the trailing side. Defaults to `end`, so the switch trails the label.
Disables the switch and prevents interaction
Optional icon rendered alongside the label. Strings starting with `lucide-` are rendered via the shared Lucide Tailwind utility; component values are rendered with `<component :is>`.
Label rendered above (or beside, for binary controls) the input.
Helper text rendered below the input. Hidden when `error` is set. A `#description` slot is not: it renders beside the error, and is referenced alongside it.
Error message rendered below the input. When set, the control receives `aria-invalid="true"` and `data-state="invalid"`. Takes a string, an array of strings, or an `Error` whose `messages` are rendered as stacked lines (with `Error.message` as the fallback). This is the same value `ErrorMessage.message` takes. An empty array and an empty string both mean no error.
Marks the field as required. Renders an asterisk next to the label, with `sr-only` text that announces it, and forwards `required` / `aria-required` to the underlying control where the control's role allows it. `data-required` is set either way.
HTML id of the underlying control. Auto-generated via `useId()` if omitted.
| Slot | Payload |
|---|---|
label | { required: boolean; } Overrides the rendered label content. Receives `{ required }`. |
description | — Overrides the rendered description content. |
Overrides the rendered label content. Receives `{ required }`.
Overrides the rendered description content.
| Event | Payload |
|---|---|
update:modelValue | [value: boolean] Fired when the model value changes. |
Fired when the model value changes.
| Template ref | Type |
|---|---|
focus | (options?: FocusOptions) => void Moves focus to the switch. |
Moves focus to the switch.