Switch

A toggle input for turning options on or off. Clearly indicates state changes and allows quick, intuitive control.

vue
<script setup lang="ts">
import { ref } from 'vue'
import { Switch } from 'frappe-ui'

const enabled = ref(false)
</script>

<template>
  <Switch v-model="enabled" label="Enable notifications" />
</template>

Sizes

vue
<script setup lang="ts">
import { Switch } from 'frappe-ui'
</script>

<template>
  <div class="flex flex-col gap-3 items-start">
    <Switch size="sm" label="Small" />
    <Switch size="md" label="Medium" />
  </div>
</template>

With icon

Strings starting with lucide- route through the shared Lucide Tailwind utility. Component values are rendered with <component :is>.

A weekly summary delivered every Friday.

vue
<script setup lang="ts">
import { Switch } from 'frappe-ui'
</script>

<template>
  <div class="flex flex-col gap-3 items-start">
    <Switch icon="lucide-bell" label="Notifications" />
    <Switch
      icon="lucide-mail"
      label="Email digest"
      description="A weekly summary delivered every Friday."
    />
  </div>
</template>

Labeling

Get notified when something happens.

vue
<script setup lang="ts">
import { computed, ref } from 'vue'
import { Checkbox, Switch } from 'frappe-ui'

const enabled = ref(false)
const required = ref(true)
const showError = ref(false)

const error = computed(() =>
  showError.value ? 'You must enable this to continue.' : '',
)
</script>

<template>
  <div class="flex gap-8 items-start">
    <Switch
      v-model="enabled"
      label="Enable notifications"
      description="Get notified when something happens."
      :error="error"
      :required="required"
      class="w-72"
    />
    <div
      class="flex flex-col gap-2 items-start border-l border-outline-gray-2 pl-6"
    >
      <Checkbox v-model="required" label="required" />
      <Checkbox v-model="showError" label="show error" />
    </div>
  </div>
</template>

States

vue
<script setup lang="ts">
import { Switch } from 'frappe-ui'
</script>

<template>
  <div class="flex flex-col gap-3 items-start">
    <Switch label="Default" />
    <Switch label="Required" required />
    <Switch label="Disabled" disabled />
    <Switch label="With error" error="You must enable this to continue." />
  </div>
</template>

Deprecated change emit

The change emit is kept for backwards compatibility and will fire a dev-mode [frappe-ui] Switch.change is deprecated. Use update:modelValue / v-model instead. warning when bound. Use v-model / update:modelValue instead.

vue
<script setup lang="ts">
import { Switch } from 'frappe-ui'

function onChange(value: boolean) {
  console.log('Switch changed:', value)
}
</script>

<!--
  The `change` emit is deprecated. Use `v-model` / `update:modelValue`
  instead. Toggling this switch will fire a one-time
  `[frappe-ui] Switch.change is deprecated` warning in the console.
-->

<template>
  <Switch label="Toggle me" @change="onChange" />
</template>

API Reference

Show types
typescript
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

  /** 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

  /**
   * Custom classes applied to the label element.
   * @deprecated Use `data-*` styling hooks instead.
   */
  labelClasses?: string
}
size
= "sm"
ToggleSize

Size of the switch control

disabled
= false
boolean

Disables the switch and prevents interaction

icon
string | Component

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>`.

labelClasses
= ""

Deprecated — Use `data-*` styling hooks instead.

label
string

Label rendered above (or beside, for binary controls) the input.

description
string

Helper text rendered below the input. Hidden when `error` is set.

error
string | FrappeUIError

Error message rendered below the input. When set, the control receives `aria-invalid="true"` and `data-state="invalid"`. May be either a string or an `Error` object whose `messages?: string[]` is rendered as stacked lines (with `Error.message` as the fallback).

required
boolean

Marks the field as required. Renders an asterisk next to the label and forwards `required` / `aria-required` to the underlying control.

id
string

HTML id of the underlying control. Auto-generated via `useId()` if omitted.

modelValue
= false
boolean
label
{ required: boolean; }

Overrides the rendered label content. Receives `{ required }`.

description

Overrides the rendered description content.

update:modelValue
[value: boolean]

Fired when the model value changes.