A comprehensive, accessible, and highly customizable toggle switch component for Svelte applications. Built with TypeScript and designed with accessibility in mind.
⨠5 Design Variants: Slider (iOS), Inner, Modern, Material, and Multi-option
šØ Multiple Color Schemes: 6 built-in schemes + custom colors
š 5 Size Options: From extra small to extra large
āæ Fully Accessible: ARIA attributes, keyboard navigation, screen reader support
š State Management: Disabled, loading, and read-only states
šÆ Icon Support: Custom icons with flexible positioning
ā” Smooth Animations: Customizable duration and easing
š¦ TypeScript: Full TypeScript support with proper types
š Flexible Styling: Shadow, outline, and label positioning options
š Modern Stack: Built with Svelte 5, Vite 6, and TypeScript 5
npm install svelte-toggle-switch
yarn add svelte-toggle-switch
pnpm add svelte-toggle-switch
<script>
import Switch from 'svelte-toggle-switch';
let enabled = false;
</script>
<Switch bind:value={enabled} label="Enable notifications" />
The default design, inspired by iOS toggles.
<Switch bind:value={enabled} label="Enable dark mode" design="slider" />
Toggle with visible ON/OFF text inside the button.
<Switch bind:value={enabled} label="Auto-save" design="inner" />
Enhanced slider with optional icon displays on the track.
<Switch
bind:value={enabled}
label="Wi-Fi"
design="modern"
showIcons={true}
onIcon="ā"
offIcon="ā"
/>
Google Material Design inspired toggle.
<Switch bind:value={enabled} label="Bluetooth" design="material" />
Radio group styled as a segmented control.
<Switch
bind:value={selectedOption}
label="View mode"
design="multi"
options={['Grid', 'List', 'Table']}
/>
6 built-in color schemes plus custom color support.
<!-- Built-in schemes -->
<Switch bind:value={enabled} colorScheme="blue" />
<Switch bind:value={enabled} colorScheme="green" />
<Switch bind:value={enabled} colorScheme="red" />
<Switch bind:value={enabled} colorScheme="purple" />
<Switch bind:value={enabled} colorScheme="orange" />
<Switch bind:value={enabled} colorScheme="pink" />
<!-- Custom colors -->
<Switch
bind:value={enabled}
colorScheme="custom"
color="#FF6B6B"
offColor="#F0F0F0"
/>
<Switch bind:value={enabled} size="xs" label="Extra Small" />
<Switch bind:value={enabled} size="sm" label="Small" />
<Switch bind:value={enabled} size="md" label="Medium (Default)" />
<Switch bind:value={enabled} size="lg" label="Large" />
<Switch bind:value={enabled} size="xl" label="Extra Large" />
<!-- Custom size (in rem) -->
<Switch bind:value={enabled} size={2} label="Custom Size" />
<Switch bind:value={enabled} label="Disabled" disabled />
Shows a spinner animation.
<Switch bind:value={enabled} label="Loading..." loading />
Displays current state without allowing changes.
<Switch bind:value={enabled} label="Read-only" readonly />
Add custom icons to your toggles.
<!-- Slider with icons -->
<Switch
bind:value={enabled}
label="Theme"
showIcons={true}
onIcon="š"
offIcon="ā"
/>
<!-- Modern design with track icons -->
<Switch
bind:value={enabled}
label="Airplane Mode"
design="modern"
showIcons={true}
onIcon="ā"
offIcon="ā"
/>
<Switch
bind:value={enabled}
label="Label on left"
labelPosition="left"
/>
<!-- With shadow -->
<Switch bind:value={enabled} label="Shadow effect" shadow />
<!-- With outline -->
<Switch bind:value={enabled} label="Outline style" outline />
<!-- Without rounded corners (inner design only) -->
<Switch bind:value={enabled} design="inner" rounded={false} />
<Switch
bind:value={enabled}
label="Custom animation"
animationDuration={800}
animationEasing="cubic-bezier(0.68, -0.55, 0.265, 1.55)"
/>
<Switch
bind:value={enabled}
id="custom-id"
ariaLabel="Toggle notifications"
ariaDescribedBy="notification-description"
/>
| Prop | Type | Default | Description |
|---|---|---|---|
value |
boolean | string |
false |
Current value (use with bind:value) |
label |
string |
'' |
Label text displayed next to the switch |
design |
'inner' | 'slider' | 'modern' | 'ios' | 'material' | 'multi' |
'slider' |
Visual design variant |
options |
string[] |
[] |
Options array (required for multi design) |
size |
'xs' | 'sm' | 'md' | 'lg' | 'xl' | number |
'md' |
Size variant or custom size in rem |
color |
string |
'#007AFF' |
Custom active color (CSS color value) |
offColor |
string |
'#E5E7EB' |
Custom inactive color (CSS color value) |
colorScheme |
'blue' | 'green' | 'red' | 'purple' | 'orange' | 'pink' | 'custom' |
'blue' |
Built-in color scheme |
disabled |
boolean |
false |
Disables interaction |
loading |
boolean |
false |
Shows loading spinner |
readonly |
boolean |
false |
Makes switch read-only |
showIcons |
boolean |
false |
Display icons on the switch |
onIcon |
string |
'ā' |
Icon shown when active |
offIcon |
string |
'ā' |
Icon shown when inactive |
animationDuration |
number |
300 |
Animation duration in milliseconds |
animationEasing |
string |
'ease-in-out' |
CSS easing function |
ariaLabel |
string |
'' |
ARIA label for accessibility |
ariaDescribedBy |
string |
'' |
ARIA described-by attribute |
id |
string |
auto-generated | Custom element ID |
labelPosition |
'left' | 'right' |
'right' |
Position of the label |
rounded |
boolean |
true |
Use rounded corners (inner design) |
shadow |
boolean |
false |
Add box shadow |
outline |
boolean |
false |
Add border outline |
This component follows WAI-ARIA best practices:
role="switch" and role="radiogroup" attributesaria-checked state managementaria-labelledby and aria-describedby support:focus-visibleThis package includes TypeScript definitions. All props are fully typed for the best development experience.
import type { ComponentProps } from 'svelte';
import Switch from 'svelte-toggle-switch';
type SwitchProps = ComponentProps<Switch>;
<script>
let darkMode = false;
$: if (darkMode) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
</script>
<Switch
bind:value={darkMode}
label="Dark mode"
showIcons={true}
onIcon="š"
offIcon="ā"
colorScheme="purple"
/>
<script>
let formData = {
notifications: false,
marketing: false,
newsletter: true
};
</script>
<form>
<Switch bind:value={formData.notifications} label="Push notifications" />
<Switch bind:value={formData.marketing} label="Marketing emails" />
<Switch bind:value={formData.newsletter} label="Newsletter" />
</form>
<script>
let enabled = false;
let loading = false;
async function handleToggle() {
loading = true;
try {
await api.updateSetting(enabled);
} catch (error) {
// Revert on error
enabled = !enabled;
} finally {
loading = false;
}
}
$: if (enabled !== undefined) {
handleToggle();
}
</script>
<Switch bind:value={enabled} {loading} label="Enable feature" />
# Install dependencies
npm install
# Start development server
npm run dev
# Build for production
npm run build
# Type checking
npm run check
Contributions are welcome! Please feel free to submit a Pull Request.
MIT Ā© Ishan Karunaratne
Major Rewrite - Complete redesign with modern features: