---
title: "Switch"
description: "A control that toggles between two states."
canonical_url: "https://vinicunca.dev/pohon/components/switch"
---
# Switch

> A control that toggles between two states.

## Usage

Use the `v-model` directive to control the checked state of the Switch.

```vue
<script setup lang="ts">
const value = ref(true)
</script>

<template>
  <PSwitch v-model="value" />
</template>
```

Use the `default-value` prop to set the initial value when you do not need to control its state.

```vue
<template>
  <PSwitch default-value />
</template>
```

### Label

Use the `label` prop to set the label of the Switch.

```vue
<template>
  <PSwitch label="Check me" />
</template>
```

When using the `required` prop, an asterisk is added next to the label.

```vue
<template>
  <PSwitch required label="Check me" />
</template>
```

### Description

Use the `description` prop to set the description of the Switch.

```vue
<template>
  <PSwitch label="Check me" description="This is a checkbox." />
</template>
```

### Icon

Use the `checked-icon` and `unchecked-icon` props to set the icons of the Switch when checked and unchecked.

```vue
<template>
  <PSwitch unchecked-icon="i-lucide-x" checked-icon="i-lucide-check" default-value label="Check me" />
</template>
```

### Loading

Use the `loading` prop to show a loading icon on the Switch.

```vue
<template>
  <PSwitch loading default-value label="Check me" />
</template>
```

### Loading Icon

Use the `loading-icon` prop to customize the loading icon. Defaults to `i-lucide-loader-circle`.

```vue
<template>
  <PSwitch loading loading-icon="i-lucide-loader" default-value label="Check me" />
</template>
```

**Nuxt:**

> [!TIP]
> See: /pohon/getting-started/integrations/icons/nuxt#theme
> 
> You can customize this icon globally in your `app.config.ts` under `ui.icons.loading` key.

**Vue:**

> [!TIP]
> See: /pohon/getting-started/integrations/icons/vue#theme
> 
> You can customize this icon globally in your `vite.config.ts` under `ui.icons.loading` key.

### Color

Use the `color` prop to change the color of the Switch.

```vue
<template>
  <PSwitch color="neutral" default-value label="Check me" />
</template>
```

### Size

Use the `size` prop to change the size of the Switch.

```vue
<template>
  <PSwitch size="xl" default-value label="Check me" />
</template>
```

### Disabled

Use the `disabled` prop to disable the Switch.

```vue
<template>
  <PSwitch disabled label="Check me" />
</template>
```

## API

### Props

```ts
/**
 * Props for the Switch component
 */
interface SwitchProps {
}
```

> [!NOTE]
> See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attributes
> 
> This component also supports all native `<button>` HTML attributes.

### Slots

```ts
/**
 * Slots for the Switch component
 */
interface SwitchSlots {
}
```

### Emits

No events available for this component.

## Theme

```ts [app.config.ts]
export default defineAppConfig({
  ui: {
    switch: {
      slots: {
        root: 'relative flex items-start',
        base: [
          'border-2 border-transparent rounded-full inline-flex shrink-0 items-center focus-visible:outline-3 data-[state=unchecked]:bg-background-accented',
          'transition-[background-color]-280 ease-out'
        ],
        container: 'flex items-center',
        thumb: 'group rounded-full bg-background flex pointer-events-none ring-0 shadow-lg transition-transform-280 ease-out items-center justify-center data-[state=unchecked]:translate-x-0 motion-reduce:transition-none data-[state=unchecked]:rtl:-translate-x-0',
        icon: [
          'opacity-0 shrink-0 size-10/12 absolute group-data-[state=unchecked]:color-text-dimmed',
          'transition-[color,opacity]-280 ease-out'
        ],
        wrapper: 'ms-2',
        label: 'block font-500 color-text',
        description: 'color-text-muted'
      },
      variants: {
        color: {
          primary: {
            base: 'data-[state=checked]:bg-primary outline-primary/25',
            icon: 'group-data-[state=checked]:color-primary'
          },
          secondary: {
            base: 'data-[state=checked]:bg-secondary outline-secondary/25',
            icon: 'group-data-[state=checked]:color-secondary'
          },
          success: {
            base: 'data-[state=checked]:bg-success outline-success/25',
            icon: 'group-data-[state=checked]:color-success'
          },
          info: {
            base: 'data-[state=checked]:bg-info outline-info/25',
            icon: 'group-data-[state=checked]:color-info'
          },
          warning: {
            base: 'data-[state=checked]:bg-warning outline-warning/25',
            icon: 'group-data-[state=checked]:color-warning'
          },
          error: {
            base: 'data-[state=checked]:bg-error outline-error/25',
            icon: 'group-data-[state=checked]:color-error'
          },
          neutral: {
            base: 'data-[state=checked]:bg-background-inverted outline-border-inverted/25',
            icon: 'group-data-[state=checked]:color-text-highlighted'
          }
        },
        size: {
          xs: {
            base: 'w-7',
            container: 'h-4',
            thumb: 'size-3 data-[state=checked]:translate-x-3 data-[state=checked]:rtl:-translate-x-3',
            wrapper: 'text-xs'
          },
          sm: {
            base: 'w-8',
            container: 'h-4',
            thumb: 'size-3.5 data-[state=checked]:translate-x-3.5 data-[state=checked]:rtl:-translate-x-3.5',
            wrapper: 'text-xs'
          },
          md: {
            base: 'w-9',
            container: 'h-5',
            thumb: 'size-4 data-[state=checked]:translate-x-4 data-[state=checked]:rtl:-translate-x-4',
            wrapper: 'text-sm'
          },
          lg: {
            base: 'w-10',
            container: 'h-5',
            thumb: 'size-4.5 data-[state=checked]:translate-x-4.5 data-[state=checked]:rtl:-translate-x-4.5',
            wrapper: 'text-sm'
          },
          xl: {
            base: 'w-11',
            container: 'h-6',
            thumb: 'size-5 data-[state=checked]:translate-x-5 data-[state=checked]:rtl:-translate-x-5',
            wrapper: 'text-base'
          }
        },
        checked: {
          true: {
            icon: 'group-data-[state=checked]:opacity-100'
          }
        },
        unchecked: {
          true: {
            icon: 'group-data-[state=unchecked]:opacity-100'
          }
        },
        loading: {
          true: {
            icon: 'animate-spin'
          }
        },
        highlight: {
          true: ''
        },
        required: {
          true: {
            label: "after:color-error after:ms-0.5 after:content-['*']"
          }
        },
        disabled: {
          true: {
            root: 'opacity-75',
            base: 'cursor-not-allowed',
            label: 'cursor-not-allowed',
            description: 'cursor-not-allowed'
          }
        }
      },
      compoundVariants: [
        {
          color: 'primary',
          highlight: true,
          class: {
            base: 'ring ring-primary'
          }
        },
        {
          color: 'secondary',
          highlight: true,
          class: {
            base: 'ring ring-secondary'
          }
        },
        {
          color: 'success',
          highlight: true,
          class: {
            base: 'ring ring-success'
          }
        },
        {
          color: 'info',
          highlight: true,
          class: {
            base: 'ring ring-info'
          }
        },
        {
          color: 'warning',
          highlight: true,
          class: {
            base: 'ring ring-warning'
          }
        },
        {
          color: 'error',
          highlight: true,
          class: {
            base: 'ring ring-error'
          }
        },
        {
          color: 'neutral',
          highlight: true,
          class: {
            base: 'ring ring-border-inverted'
          }
        }
      ],
      defaultVariants: {
        color: 'primary',
        size: 'md'
      }
    }
  }
})
```

## Changelog

See commit history for [component](https://github.com/vinicunca/pohon/commits/main/src/runtime/components/Switch.vue) and [theme](https://github.com/vinicunca/pohon/commits/main/src/theme/switch.ts).

---

- [Switch](https://vinicunca.dev/akar/components/switch)
- [GitHub](https://github.com/vinicunca/pohon/blob/main/src/runtime/components/Switch.vue)


## Sitemap

See the full [sitemap](https://vinicunca.dev/sitemap.md) for all pages.
