Installation
Install the dependencies
pnpm add cn github:sveltery/baseCopy the component
Copy the following files into src/lib/components/ui/switch.
<script lang="ts">
import { Switch as Primitive } from '@sveltery/base/switch';
import { cn } from 'cn';
import type { SwitchProps } from './types.js';
let { checked = $bindable(), class: classProp, size = 'default', ...props }: SwitchProps = $props();
</script>
<Primitive.Root data-slot="switch" data-size={size} bind:checked {...props} class={cn('data-checked:bg-primary data-unchecked:bg-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 dark:data-unchecked:bg-input/80 shrink-0 rounded-full border border-transparent focus-visible:ring-3 aria-invalid:ring-3 group-has-[:focus-visible]/field-label:ring-0 group-has-[:focus-visible]/field-label:border-transparent data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] peer group/switch relative inline-flex items-center transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 data-disabled:cursor-not-allowed data-disabled:opacity-50', classProp)}>
<Primitive.Thumb data-slot="switch-thumb" class="bg-background dark:data-unchecked:bg-foreground dark:data-checked:bg-primary-foreground rounded-full group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 pointer-events-none block ring-0 transition-transform" />
</Primitive.Root>import type { SwitchRootProps } from '@sveltery/base/switch';
export type SwitchProps = SwitchRootProps & { size?: 'sm' | 'default' };
export type { SwitchRootState as SwitchState } from '@sveltery/base/switch';export { default as Switch } from './Switch.svelte';
export type { SwitchProps, SwitchState } from './types.js';Update the import paths
Change the imports to match your project setup.
Usage
<script lang="ts">
import { Switch } from '$lib/components/ui/switch';
import { Label } from '$lib/components/ui/label';
</script><div class="flex items-center gap-2">
<Switch id="airplane-mode" />
<Label for="airplane-mode">Airplane Mode</Label>
</div>Checked state
Bind checked to read and write the state. defaultChecked is the state an unbound switch starts from, as on an HTML checkbox.
<script lang="ts">
let enabled = $state(false);
</script>
<Switch bind:checked={enabled} />
<Switch defaultChecked />Forms
Switch renders a hidden checkbox, so it submits with its form. A checked switch submits value (default on) under name.
<form method="POST">
<Switch name="notifications" value="enabled" defaultChecked />
<button type="submit">Save</button>
</form>Sizes
size is sm or default.
<Switch size="sm" />API reference
Switch is styled on top of the Sveltery Base Switch primitive, which owns its state, keyboard behavior, form value and accessibility. See the Base UI Switch documentation for the behavior it ports.