Appearance
@vibe-labs/design-components-toggles
Toggle/switch component tokens, styles, and TypeScript types for the Vibe Design System.
Installation
css
@import "@vibe-labs/design-components-toggles";ts
import { ToggleSizes } from "@vibe-labs/design-components-toggles/types";
import type { ToggleSize, ToggleStyleProps } from "@vibe-labs/design-components-toggles/types";Contents
Tokens (toggle.css)
CSS custom properties defined in @layer vibe.tokens:
Track
| Token | sm | md | lg |
|---|---|---|---|
--toggle-width-{size} | 2rem | 2.5rem | 3rem |
--toggle-height-{size} | 1.125rem | 1.375rem | 1.625rem |
| Token | Default | Description |
|---|---|---|
--toggle-radius | --radius-full | Track border radius |
--toggle-bg | --surface-overlay | Unchecked background |
--toggle-bg-checked | --color-accent | Checked background |
--toggle-border-width | --border-width-1 | Border width |
--toggle-border-color | --border-default | Unchecked border |
--toggle-border-color-checked | --color-accent | Checked border |
Thumb
| Token | sm | md | lg |
|---|---|---|---|
--toggle-thumb-size-{size} | 0.875rem | 1.125rem | 1.375rem |
| Token | Default | Description |
|---|---|---|
--toggle-thumb-color | --color-neutral-0 | Thumb color (white) |
--toggle-thumb-shadow | --shadow-xs | Thumb elevation |
--toggle-thumb-inset | 2px | Gap between thumb and track edge |
Generated Styles (toggle.g.css)
Component classes generated into @layer vibe.components.
Elements
- toggle — inline-flex track with hidden native input, transition on background/border
- toggle-thumb — circular knob with shadow, slides via
translateXon checked - toggle-field — inline-flex wrapper for toggle + label text
Sizes
sm · md · lg (default: md) — thumb travel distance auto-calculated per size from width - thumb - inset - border*2
States
- Checked — accent background/border, thumb slides to end position (via
:has(input:checked)) - Disabled — reduced opacity, not-allowed cursor
- Focus visible — ring via box-shadow
TypeScript Types (types/)
ts
ToggleSizes // ["sm", "md", "lg"]
type ToggleSize
interface ToggleStyleProps { size?: ToggleSize; disabled?: boolean }
interface ToggleThumbStyleProps {}
interface ToggleFieldStyleProps {}Dist Structure
| File | Description |
|---|---|
index.css | Barrel — imports tokens + generated styles |
toggle.css | Token definitions |
toggle.g.css | Generated component styles |
index.js / index.d.ts | TypeScript types + runtime constants |
Dependencies
Requires tokens from @vibe-labs/design (colors, surfaces, borders, spacing, transitions, elevation).
Build
bash
npm run buildUsage Guide
Import
css
@import "@vibe-labs/design-components-toggles";ts
import { ToggleSizes } from "@vibe-labs/design-components-toggles/types";
import type { ToggleStyleProps } from "@vibe-labs/design-components-toggles/types";Variants
| Attribute / Flag | Values | Notes |
|---|---|---|
data-size | sm md lg | Default: md |
data-disabled | boolean flag | Reduced opacity, not-allowed cursor |
Checked state is driven by input:checked inside .toggle (uses :has()). No separate data attribute needed.
Examples
Basic toggle
html
<label class="toggle">
<input type="checkbox" />
<div class="toggle-thumb"></div>
</label>Pre-checked toggle
html
<label class="toggle">
<input type="checkbox" checked />
<div class="toggle-thumb"></div>
</label>Sizes
html
<label class="toggle" data-size="sm">
<input type="checkbox" />
<div class="toggle-thumb"></div>
</label>
<label class="toggle" data-size="md">
<input type="checkbox" checked />
<div class="toggle-thumb"></div>
</label>
<label class="toggle" data-size="lg">
<input type="checkbox" />
<div class="toggle-thumb"></div>
</label>Disabled toggle
html
<label class="toggle" data-disabled>
<input type="checkbox" disabled />
<div class="toggle-thumb"></div>
</label>
<label class="toggle" data-disabled>
<input type="checkbox" checked disabled />
<div class="toggle-thumb"></div>
</label>Toggle with label text (toggle-field)
html
<label class="toggle-field">
<span>Enable notifications</span>
<span class="toggle">
<input type="checkbox" />
<div class="toggle-thumb"></div>
</span>
</label>Toggle field with description
html
<div style="display: flex; flex-direction: column; gap: 4px;">
<label class="toggle-field">
<div>
<div>Dark mode</div>
<div style="font-size: var(--text-sm); color: var(--text-muted);">Switch to dark theme</div>
</div>
<span class="toggle">
<input type="checkbox" />
<div class="toggle-thumb"></div>
</span>
</label>
</div>With Vue
vue
<template>
<label class="toggle-field">
<span>{{ label }}</span>
<span class="toggle" :data-size="size" :data-disabled="disabled || undefined">
<input
type="checkbox"
:checked="modelValue"
:disabled="disabled"
@change="$emit('update:modelValue', ($event.target as HTMLInputElement).checked)"
/>
<div class="toggle-thumb"></div>
</span>
</label>
</template>
<script setup lang="ts">
import type { ToggleSize } from "@vibe-labs/design-components-toggles/types";
defineProps<{ modelValue: boolean; label?: string; size?: ToggleSize; disabled?: boolean }>();
defineEmits<{ 'update:modelValue': [value: boolean] }>();
</script>