Toggle
toggleuiOn/off button (different from Switch — this is shaped like a button and lives in toolbars). Three sizes, two variants. Use inside Toggle Group or standalone for "press to enable" buttons like bold / italic.
Installation
$pnpm dlx shadcn-svelte@latest add https://uipkge.dev/r/svelte/toggle.json$npx shadcn-svelte@latest add https://uipkge.dev/r/svelte/toggle.json$yarn dlx shadcn-svelte@latest add https://uipkge.dev/r/svelte/toggle.json$bunx shadcn-svelte@latest add https://uipkge.dev/r/svelte/toggle.jsonManifest:
https://uipkge.dev/r/svelte/toggle.jsonInstalls to:src/lib/components/ui/toggle/Examples
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
variant | 'default''outline' | default | optional |
size | 'default''sm''lg' | default | optional |
pressedControlled pressed state. Bind it for two-way updates. | boolean | — | optional |
defaultPressedInitial pressed state for uncontrolled use. | boolean | false | optional |
onPressedChangeCalled with the new pressed state after every toggle. | (pressed: boolean) => void | — | optional |
childemitting a <button> — the Svelte counterpart of React's `asChild`. | Snippet<[{ props: Record<string, unknown> }]> | — | optional |
ref | HTMLButtonElement | null | — | optional |
npm dependencies
Used by
Files installed (3)
src/lib/components/ui/toggle/Toggle.svelte2 kB
<script lang="ts" module> import type { Snippet } from 'svelte' import type { HTMLButtonAttributes } from 'svelte/elements' import type { ToggleVariants } from './toggle.variants' type ToggleClickEvent = Parameters<NonNullable<HTMLButtonAttributes['onclick']>>[0] export interface ToggleProps extends HTMLButtonAttributes { variant?: ToggleVariants['variant'] size?: ToggleVariants['size'] /** Controlled pressed state. Bind it for two-way updates. */ pressed?: boolean /** Initial pressed state for uncontrolled use. */ defaultPressed?: boolean /** Called with the new pressed state after every toggle. */ onPressedChange?: (pressed: boolean) => void /** Render your own element with the toggle's props and styles instead of * emitting a <button> — the Svelte counterpart of React's `asChild`. */ child?: Snippet<[{ props: Record<string, unknown> }]> ref?: HTMLButtonElement | null } </script> <script lang="ts"> import { cn } from '$lib/utils' import { toggleVariants } from './toggle.variants' let { class: className, variant = 'default', size = 'default', defaultPressed = false, pressed = $bindable(defaultPressed), disabled = false, child, children, ref = $bindable(null), onPressedChange, onclick, ...restProps }: ToggleProps = $props() function handleClick(event: ToggleClickEvent) { if (disabled) return pressed = !pressed onPressedChange?.(pressed) onclick?.(event) } const mergedProps = $derived({ 'data-uipkge': '', 'data-slot': 'toggle', 'data-variant': variant, 'data-size': size, 'data-state': pressed ? 'on' : 'off', 'aria-pressed': pressed, disabled, class: cn(toggleVariants({ variant, size }), className), onclick: handleClick, ...restProps, }) </script> {#if child} {@render child({ props: mergedProps })} {:else} <button bind:this={ref} type="button" {...mergedProps}> {@render children?.()} </button> {/if}src/lib/components/ui/toggle/toggle.variants.ts1.6 kB
import type { VariantProps } from 'class-variance-authority' import { cva } from 'class-variance-authority' /** * Variant definitions live in their own file (rather than the package * `index.ts`) so consuming Vue SFCs can import without creating a circular * dependency through the index. See card.variants.ts for the canonical * example + the SSR symptom that motivated the split. */ export const toggleVariants = cva( // Focus ring intentionally subtle: 1px ring on :focus-visible only, no // border swap. Keyboard users still get a clear focused state; mouse // users don't see a loud 3px halo after click (which lingers because // the button retains focus). Matches the segmented-control density. "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:ring-ring/50 focus-visible:ring-1 outline-none transition-colors duration-200 whitespace-nowrap", { variants: { variant: { default: 'bg-transparent', outline: 'border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground', }, size: { default: 'h-9 px-2 min-w-9', sm: 'h-8 px-1.5 min-w-8', lg: 'h-10 px-2.5 min-w-10', }, }, defaultVariants: { variant: 'default', size: 'default', }, }, ) export type ToggleVariants = VariantProps<typeof toggleVariants>src/lib/components/ui/toggle/index.ts0.3 kB
export { default as Toggle, type ToggleProps } from './Toggle.svelte' // Re-export variant API from the sibling file (kept separate to avoid the // Component <-> index.ts circular import that broke dev SSR for Card). export { toggleVariants, type ToggleVariants } from './toggle.variants'
Raw manifest:https://uipkge.dev/r/svelte/toggle.json