Switch
A toggle control for switching between two states
Basic Usage
1
2<script lang="ts">
3 import { Switch, Label } from "@kareyes/aether";
4
5 let basicSwitch = $state(false);
6</script>
7
8<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
9 <div class="space-y-2">
10 <Label for="basic-switch" class="text-sm font-medium">Basic Switch</Label>
11 <div class="flex items-center space-x-2">
12 <Switch
13 id="basic-switch"
14 bind:checked={basicSwitch}
15 />
16 <span class="text-sm text-muted-foreground">
17 {basicSwitch ? 'On' : 'Off'}
18 </span>
19 </div>
20 </div>
21
22 <div class="space-y-2">
23 <Label class="text-sm font-medium">Disabled (On)</Label>
24 <div class="flex items-center space-x-2">
25 <Switch checked={true} disabled={true} />
26 <span class="text-sm text-muted-foreground">Disabled</span>
27 </div>
28 </div>
29
30 <div class="space-y-2">
31 <Label class="text-sm font-medium">Disabled (Off)</Label>
32 <div class="flex items-center space-x-2">
33 <Switch checked={false} disabled={true} />
34 <span class="text-sm text-muted-foreground">Disabled</span>
35 </div>
36 </div>
37</div>Variants
default
success
warning
danger
ghost
1
2<script lang="ts">
3 import { Switch, SwitchPrimitives } from "@kareyes/aether";
4
5 const variants: SwitchPrimitives.SwitchVariant[] = ['default', 'success', 'warning', 'danger', 'ghost'];
6 let states = $state({
7 default: false,
8 success: false,
9 warning: false,
10 danger: false,
11 ghost: false
12 });
13</script>
14
15<div class="grid grid-cols-2 md:grid-cols-5 gap-6">
16 {#each variants as variant}
17 <div class="space-y-2">
18 <h3 class="text-sm font-medium capitalize">{variant}</h3>
19 <div class="flex items-center space-x-2">
20 <Switch
21 {variant}
22 bind:checked={states[variant]}
23 />
24 <span class="text-xs text-muted-foreground">
25 {states[variant] ? 'On' : 'Off'}
26 </span>
27 </div>
28 </div>
29 {/each}
30</div>Sizes
SM
Default
LG
1
2<script lang="ts">
3 import { Switch, SwitchPrimitives } from "@kareyes/aether";
4
5 const sizes: SwitchPrimitives.SwitchSize[] = ['sm', 'default', 'lg'];
6 let states = $state({ sm: false, default: false, lg: false });
7</script>
8
9<div class="flex flex-wrap gap-8 items-end">
10 {#each sizes as size}
11 <div class="space-y-2">
12 <h3 class="text-sm font-medium capitalize">
13 {size === 'default' ? 'Default' : size?.toUpperCase() ?? ''}
14 </h3>
15 <div class="flex items-center space-x-2">
16 <Switch
17 {size}
18 bind:checked={states[size]}
19 />
20 <span class="text-xs text-muted-foreground">
21 {states[size] ? 'On' : 'Off'}
22 </span>
23 </div>
24 </div>
25 {/each}
26</div>Error States
1
2<script lang="ts">
3 import { Switch, Label } from "@kareyes/aether";
4</script>
5
6<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
7 <div class="space-y-2">
8 <Label class="text-sm font-medium">Switch with Error</Label>
9 <div class="flex items-center space-x-2">
10 <Switch error={true} />
11 <span class="text-xs text-destructive">Required</span>
12 </div>
13 </div>
14
15 <div class="space-y-2">
16 <Label class="text-sm font-medium">Error with Variant</Label>
17 <div class="flex items-center space-x-2">
18 <Switch variant="danger" error={true} checked={true} />
19 <span class="text-xs text-destructive">Invalid state</span>
20 </div>
21 </div>
22
23 <div class="space-y-2">
24 <Label class="text-sm font-medium">Large Error Switch</Label>
25 <div class="flex items-center space-x-2">
26 <Switch size="lg" error={true} />
27 <span class="text-xs text-destructive">Confirmation required</span>
28 </div>
29 </div>
30</div>Variant & Size Combinations
Large Success
Small Warning
Large Danger
1
2<script lang="ts">
3 import { Switch } from "@kareyes/aether";
4</script>
5
6<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
7 <div class="space-y-2">
8 <h3 class="font-medium">Large Success</h3>
9 <Switch variant="success" size="lg" checked={true} />
10 </div>
11
12 <div class="space-y-2">
13 <h3 class="font-medium">Small Warning</h3>
14 <Switch variant="warning" size="sm" checked={true} />
15 </div>
16
17 <div class="space-y-2">
18 <h3 class="font-medium">Large Danger</h3>
19 <Switch variant="danger" size="lg" checked={true} />
20 </div>
21</div>Form Integration
Settings
Receive notifications via email
Receive marketing and promotional emails
Required for app functionality
1
2<script lang="ts">
3 import { Switch, Label } from "@kareyes/aether";
4
5 let formSwitch = $state(false);
6</script>
7
8<div class="max-w-md space-y-4 p-6 border border-border rounded-lg">
9 <h3 class="font-medium">Settings</h3>
10
11 <div class="space-y-4">
12 <div class="flex items-center justify-between">
13 <div class="space-y-0.5">
14 <Label for="notifications" class="text-sm font-medium">
15 Email Notifications
16 </Label>
17 <p class="text-xs text-muted-foreground">
18 Receive notifications via email
19 </p>
20 </div>
21 <Switch
22 id="notifications"
23 name="notifications"
24 bind:checked={formSwitch}
25 variant="success"
26 />
27 </div>
28
29 <div class="flex items-center justify-between">
30 <div class="space-y-0.5">
31 <Label for="marketing" class="text-sm font-medium">
32 Marketing Emails
33 </Label>
34 <p class="text-xs text-muted-foreground">
35 Receive marketing and promotional emails
36 </p>
37 </div>
38 <Switch
39 id="marketing"
40 name="marketing"
41 checked={false}
42 variant="ghost"
43 />
44 </div>
45
46 <div class="flex items-center justify-between">
47 <div class="space-y-0.5">
48 <Label class="text-sm font-medium text-muted-foreground">
49 Data Processing (Required)
50 </Label>
51 <p class="text-xs text-muted-foreground">
52 Required for app functionality
53 </p>
54 </div>
55 <Switch checked={true} disabled={true} variant="default" required={true} />
56 </div>
57 </div>
58</div>With Field Component
Field component provides structured labels, descriptions, and error handling.
Receive email notifications for updates
Automatically save your work
With Validation
Multiple Switches in Field.Set
1
2<script lang="ts">
3 import { Switch, Field, FieldPrimitives } from "@kareyes/aether";
4
5 let basicSwitch = $state(false);
6 let formSwitch = $state(false);
7</script>
8
9<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
10 <Field
11 label="Enable notifications"
12 description="Receive email notifications for updates"
13 orientation="horizontal"
14 labelPosition="before"
15 >
16 <Switch bind:checked={basicSwitch} variant="success" />
17 </Field>
18
19 <Field
20 label="Auto-save"
21 description="Automatically save your work"
22 orientation="horizontal"
23 labelPosition="before"
24 >
25 <Switch checked={true} variant="success" />
26 </Field>
27</div>
28
29<div class="space-y-4">
30 <h3 class="font-medium">With Validation</h3>
31 <Field
32 label="Accept terms and conditions"
33 description="You must accept to continue"
34 required
35 error={!formSwitch ? "Please accept the terms to continue" : undefined}
36 orientation="horizontal"
37 labelPosition="before"
38 >
39 <Switch bind:checked={formSwitch} error={!formSwitch} />
40 </Field>
41</div>
42
43<div class="space-y-4">
44 <h3 class="font-medium">Multiple Switches in Field.Set</h3>
45 <FieldPrimitives.Set>
46 <FieldPrimitives.Legend>Notification Preferences</FieldPrimitives.Legend>
47 <FieldPrimitives.Description>Configure how you want to be notified</FieldPrimitives.Description>
48 <FieldPrimitives.Separator />
49 <FieldPrimitives.Group class="gap-4">
50 <Field label="Email Notifications" description="Get notified via email"
51 orientation="horizontal" labelPosition="before">
52 <Switch variant="success" checked={true} />
53 </Field>
54 <Field label="Push Notifications" description="Get browser push notifications"
55 orientation="horizontal" labelPosition="before">
56 <Switch variant="default" checked={false} />
57 </Field>
58 <Field label="SMS Notifications" description="Get text message alerts"
59 orientation="horizontal" labelPosition="before">
60 <Switch variant="warning" checked={false} />
61 </Field>
62 </FieldPrimitives.Group>
63 </FieldPrimitives.Set>
64</div>Current State
Basic Switches
{
"basic": false,
"form": false
}Variants
{
"default": false,
"success": false,
"warning": false,
"danger": false,
"ghost": false
}Sizes
{
"sm": false,
"default": false,
"lg": false
}1
2<script lang="ts">
3 import { Switch } from "@kareyes/aether";
4
5 let states = $state({
6 basicSwitch: false,
7 formSwitch: false,
8 variants: { default: false, success: false, warning: false, danger: false, ghost: false },
9 sizes: { sm: false, default: false, lg: false }
10 });
11</script>
12
13<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
14 <div class="space-y-2">
15 <h3 class="font-medium">Basic Switches</h3>
16 <pre class="text-sm bg-muted p-4 rounded-md overflow-auto">{JSON.stringify({
17 basic: states.basicSwitch,
18 form: states.formSwitch
19 }, null, 2)}</pre>
20 </div>
21
22 <div class="space-y-2">
23 <h3 class="font-medium">Variants</h3>
24 <pre class="text-sm bg-muted p-4 rounded-md overflow-auto">{JSON.stringify(states.variants, null, 2)}</pre>
25 </div>
26
27 <div class="space-y-2">
28 <h3 class="font-medium">Sizes</h3>
29 <pre class="text-sm bg-muted p-4 rounded-md overflow-auto">{JSON.stringify(states.sizes, null, 2)}</pre>
30 </div>
31</div>Features
- Multiple Variants: default, success, warning, danger, ghost
- Three Sizes: sm, default, lg
- Error States: Built-in error state handling
- Field Integration: Works seamlessly with Field component
- Accessibility: Full keyboard navigation and ARIA support
- TypeScript: Complete type definitions
- Form Integration: Native form support with name/value attributes
Basic Usage
Simple Switch
<script>
import { Switch } from "@kareyes/aether";
let enabled = $state(false);
</script>
<Switch bind:checked={enabled} />
With Label (using Field)
<script>
import { Switch } from "@kareyes/aether";
import { Field } from "@kareyes/aether";
let notifications = $state(true);
</script>
<Field
label="Enable notifications"
description="Receive email notifications for updates"
orientation="horizontal"
labelPosition="before"
>
<Switch bind:checked={notifications} />
</Field>
Sizes
Available sizes: sm, default, lg
<Switch size="sm" />
<Switch size="default" />
<Switch size="lg" />
Variants
The Switch component supports different visual variants:
Default
Standard switch appearance for general use.
<Switch variant="default" checked={true} />
Success
Green variant for positive actions or enabled features.
<Switch variant="success" checked={true} />
Warning
Orange/yellow variant for actions requiring attention.
<Switch variant="warning" checked={true} />
Danger
Red variant for destructive or dangerous actions.
<Switch variant="danger" checked={true} />
Ghost
Subtle variant with less visual prominence.
<Switch variant="ghost" checked={true} />
States
Disabled
<Switch disabled checked={true} />
<Switch disabled checked={false} />
Error State
<script>
let accepted = $state(false);
let hasError = $derived(!accepted);
</script>
<Switch
bind:checked={accepted}
error={hasError}
onError={(err) => console.log('Error state:', err)}
/>
Form Integration
Basic Form
<form onsubmit={handleSubmit}>
<Switch
name="newsletter"
value="yes"
checked={true}
/>
</form>
Required Field
<Switch
name="terms"
required
checked={false}
/>
Using Switch with Field Component
The Field component provides a consistent way to add labels, descriptions, and error handling to your Switch components.
Basic Field Usage
<script>
import { Switch } from "@kareyes/aether";
import { Field } from "@kareyes/aether";
let autoSave = $state(true);
</script>
<Field
label="Auto-save"
description="Automatically save your work"
orientation="horizontal"
labelPosition="before"
>
<Switch
bind:checked={autoSave}
variant="success"
/>
</Field>
With Validation
<script>
import { Switch } from "@kareyes/aether";
import { Field } from "@kareyes/aether";
let termsAccepted = $state(false);
let error = $derived(!termsAccepted);
</script>
<Field
label="Accept terms and conditions"
description="You must accept to continue"
required
error={error ? "Please accept the terms to continue" : undefined}
orientation="horizontal"
labelPosition="before"
>
<Switch
bind:checked={termsAccepted}
error={error}
/>
</Field>
Multiple Switches in Form
<script>
import { Switch } from "@kareyes/aether";
import { FieldPrimitives , Field} from "@kareyes/aether";
let settings = $state({
email: true,
push: false,
sms: false
});
</script>
<FieldPrimitives.Set>
<FieldPrimitives.Legend>Notification Settings</FieldPrimitives.Legend>
<FieldPrimitives.Description>Configure how you receive notifications</FieldPrimitives.Description>
<FieldPrimitives.Separator />
<FieldPrimitives.Group class="gap-4">
<Field
label="Email Notifications"
description="Get notified via email"
orientation="horizontal"
labelPosition="before"
>
<Switch variant="success" bind:checked={settings.email} />
</Field>
<Field
label="Push Notifications"
description="Get browser push notifications"
orientation="horizontal"
labelPosition="before"
>
<Switch bind:checked={settings.push} />
</Field>
<Field
label="SMS Notifications"
description="Get text message alerts"
orientation="horizontal"
labelPosition="before"
>
<Switch variant="warning" bind:checked={settings.sms} />
</Field>
</FieldPrimitives.Group>
</FieldPrimitives.Set>
Horizontal Layout (Label After)
<Field
label="Enable dark mode"
orientation="horizontal"
labelPosition="after"
>
<Switch checked={false} />
</Field>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
checked |
boolean |
false |
Whether the switch is checked |
variant |
'default' | 'success' | 'warning' | 'danger' | 'ghost' |
'default' |
Visual variant |
size |
'sm' | 'default' | 'lg' |
'default' |
Size of the switch |
disabled |
boolean |
false |
Whether the switch is disabled |
required |
boolean |
false |
Whether the field is required |
error |
boolean |
false |
Error state |
name |
string |
- | Name attribute for forms |
value |
string |
'on' |
Value attribute for forms |
onCheckedChange |
(checked: boolean) => void |
- | Callback when checked state changes |
onError |
(error: boolean) => void |
- | Callback when error state changes |
Events
onCheckedChange
Called whenever the switch's checked state changes.
<Switch
onCheckedChange={(checked) => {
console.log('Switch toggled:', checked);
}}
/>
onError
Called when the error state changes.
<Switch
error={true}
onError={(hasError) => {
console.log('Error state changed:', hasError);
}}
/>
Accessibility
- Uses native
<button>withrole="switch" - Proper
aria-checkedstate management aria-invalidfor error statesaria-requiredfor required fields- Full keyboard support (Space/Enter to toggle)
- Screen reader announcements for state changes
Best Practices
Use Appropriate Variants
- Default: General settings and preferences
- Success: Confirmed or enabled features (auto-save, syncing)
- Warning: Actions requiring attention (beta features, experimental)
- Danger: Destructive or dangerous actions (delete on exit, permanent changes)
- Ghost: Secondary or less important options
Provide Clear Labels
Always use the Field component or proper labels to make the purpose of the switch clear:
<!-- Good -->
<Field
label="Enable notifications"
description="Receive updates about your account"
orientation="horizontal"
>
<Switch />
</Field>
<!-- Avoid: No context for what the switch controls -->
<Switch />
Validation
For required switches, provide clear error messages:
<Field
label="Accept privacy policy"
required
error={!accepted ? "You must accept the privacy policy" : undefined}
orientation="horizontal"
>
<Switch bind:checked={accepted} error={!accepted} />
</Field>
Form Structure
Group related switches using Field.Set:
<FieldPrimitives.Set>
<FieldPrimitives.Legend>Privacy Settings</FieldPrimitives.Legend>
<FieldPrimitives.Description>Control your privacy preferences</FieldPrimitives.Description>
<FieldPrimitives.Separator />
<FieldPrimitives.Group class="gap-4">
<!-- Multiple switches here -->
</FieldPrimitives.Group>
</FieldPrimitives.Set>
Common Patterns
Settings Panel
<div class="space-y-4 max-w-md">
<Field
label="Email Notifications"
description="Receive notifications via email"
orientation="horizontal"
labelPosition="before"
>
<Switch variant="success" checked={true} />
</Field>
<Field
label="Marketing Emails"
description="Receive promotional emails"
orientation="horizontal"
labelPosition="before"
>
<Switch variant="ghost" checked={false} />
</Field>
<Field
label="Data Processing"
description="Required for app functionality"
orientation="horizontal"
labelPosition="before"
>
<Switch disabled checked={true} />
</Field>
</div>
Feature Flags
<FieldPrimitives.Set>
<FieldPrimitives.Legend>Experimental Features</FieldPrimitives.Legend>
<FieldPrimitives.Description>Enable beta features at your own risk</FieldPrimitives.Description>
<FieldPrimitives.Separator />
<FieldPrimitives.Group class="gap-4">
<Field
label="New Dashboard"
description="Try our redesigned dashboard"
orientation="horizontal"
labelPosition="before"
>
<Switch variant="warning" />
</Field>
<Field
label="AI Assistant"
description="Get help from our AI"
orientation="horizontal"
labelPosition="before"
>
<Switch variant="success" />
</Field>
</FieldPrimitives.Group>
</FieldPrimitives.Set>
Consent Management
<FieldPrimitives.Set>
<FieldPrimitives.Legend>Cookie Preferences</FieldPrimitives.Legend>
<FieldPrimitives.Description>Manage your cookie settings</FieldPrimitives.Description>
<FieldPrimitives.Separator />
<FieldPrimitives.Group class="gap-4">
<Field
label="Essential Cookies"
description="Required for site functionality"
orientation="horizontal"
labelPosition="before"
>
<Switch disabled checked={true} />
</Field>
<Field
label="Analytics Cookies"
description="Help us improve our service"
orientation="horizontal"
labelPosition="before"
>
<Switch variant="ghost" />
</Field>
<Field
label="Marketing Cookies"
description="Personalized advertising"
orientation="horizontal"
labelPosition="before"
>
<Switch variant="ghost" />
</Field>
</FieldPrimitives.Group>
</FieldPrimitives.Set>
Related Components
- Checkbox: Use for multiple selections or single opt-in scenarios
- Radio: Use for selecting one option from multiple choices
- Field: Wrapper component for consistent form layouts