Switch
Un ajuste de encendido y apagado con una presión rápida y un control que cede un poco mientras se sostiene.
Instalación
$ pnpm dlx shadcn@latest add @ssntl/switchUso
import { Switch, SwitchField } from "@/components/ui/switch"
<SwitchField label="Aceptar pedidos" hint="Los clientes pueden comprar ahora" defaultChecked />
<Switch aria-label="Modo vacaciones" />Reglas
Lo que este componente espera de ti, tal como se instala en components/ui/switch.md junto al código. El archivo completo agrega cuándo usarlo, teclado, los fundamentos de UI que aplica y cada regla compartida (en inglés).
## Reglas de Switch
- **Respuesta del interruptor.** La barra se presiona a 0.96 en 150ms, pequeño e inmediato.
- **Compresión y estiramiento.** Mientras se sostiene, el control se ensancha 6% y se aplana 6%, y luego regresa.
- Encendido llena la barra con primary, así el estado se lee sin el movimiento.
- Usa un switch para un ajuste que aplica al instante; usa un Checkbox dentro de un formulario que se envía.Código
"use client"
import * as React from "react"
import { Switch as SwitchPrimitive } from "radix-ui"
import { cn } from "@/lib/utils"
// An on/off setting that applies at once (Radix Switch, role="switch").
// - Toggle feedback: the track presses to 0.96 in 150ms, small and quick.
// - Squash & stretch: while held, the thumb widens 6% and flattens 6%, a
// hint of physical give; it springs back on release.
// - State never rides on motion alone: on fills the track with primary.
function Switch({
className,
...props
}: React.ComponentProps<typeof SwitchPrimitive.Root>) {
return (
<SwitchPrimitive.Root
data-slot="switch"
className={cn(
"group inline-flex h-8 w-13 shrink-0 cursor-pointer items-center rounded-full bg-input p-1",
"transition-[background-color,scale] duration-(--duration-fast) ease-out active:scale-(--es-press) motion-reduce:active:scale-100",
"data-[state=checked]:bg-primary",
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring disabled:cursor-not-allowed disabled:opacity-40",
className
)}
{...props}
>
<SwitchPrimitive.Thumb
data-slot="switch-thumb"
className={cn(
"pointer-events-none block size-6 rounded-full bg-card elevation-1",
"transition-[translate,scale] duration-(--duration-fast) ease-out data-[state=checked]:translate-x-5 rtl:data-[state=checked]:-translate-x-5",
"group-active:scale-x-106 group-active:scale-y-94 motion-reduce:transition-none motion-reduce:group-active:scale-100"
)}
/>
</SwitchPrimitive.Root>
)
}
/** A full-width row: the label, an optional hint, and the switch at the end. */
function SwitchField({
label,
hint,
id,
...props
}: React.ComponentProps<typeof Switch> & { label: string; hint?: string }) {
const generated = React.useId()
const controlId = id ?? generated
return (
<div
data-slot="switch-field"
className="flex min-h-12 items-center justify-between gap-4 py-2"
>
<label
htmlFor={controlId}
className="grid cursor-pointer gap-0.5 select-none"
>
<span className="text-body">{label}</span>
{hint && (
<span className="text-caption text-muted-foreground">{hint}</span>
)}
</label>
<Switch id={controlId} {...props} />
</div>
)
}
export { Switch, SwitchField }