Switch
Ajustes que aplican al instante, sin botón Guardar.
Interruptor controlado de Configuración. Replica SettingsToggleRow: label y descripción a la izquierda, switch a la derecha. El caller decide cuándo persistir el cambio.
Instalación
shadcn
npx shadcn@latest add https://design.moodinary.com/r/switch.jsonimport
import { Switch } from "@moodinary/ui/components/switch";Ejemplos
Activo, apagado y deshabilitado
Un pulso por día y Resumen semanal por email son ajustes reales del dashboard. El tercer control muestra un estado deshabilitado ilustrativo.
Bloquear que la misma persona envíe más de un pulso por día.
Stats de la semana, alertas y proyecciones por email.
Código
default.tsx
"use client";
import { Label } from "@moodinary/ui/components/label";
import { Switch } from "@moodinary/ui/components/switch";
import { useState } from "react";
export default function SwitchDefault() {
const [limit, setLimit] = useState(true);
const [digest, setDigest] = useState(false);
return (
<div className="flex w-full max-w-xl flex-col gap-4">
<div className="flex items-center justify-between gap-4 rounded-[10px] border border-line p-4">
<div className="min-w-0 space-y-0.5">
<Label className="font-medium text-sm" htmlFor="pulse-limit">
Un pulso por día
</Label>
<p className="text-muted-foreground text-xs">
Bloquear que la misma persona envíe más de un pulso por día.
</p>
</div>
<Switch checked={limit} id="pulse-limit" onCheckedChange={setLimit} />
</div>
<div className="flex items-center justify-between gap-4 rounded-[10px] border border-line p-4">
<div className="min-w-0 space-y-0.5">
<Label className="font-medium text-sm" htmlFor="weekly-digest">
Resumen semanal por email
</Label>
<p className="text-muted-foreground text-xs">
Stats de la semana, alertas y proyecciones por email.
</p>
</div>
<Switch
checked={digest}
id="weekly-digest"
onCheckedChange={setDigest}
/>
</div>
<div className="flex items-center justify-between gap-4 rounded-[10px] border border-line p-4">
<Label htmlFor="disabled-switch">Deshabilitado (demostración)</Label>
<Switch
checked={false}
disabled
id="disabled-switch"
onCheckedChange={() => undefined}
/>
</div>
</div>
);
}Props
Switch
| Prop | Tipo | Default | Descripción |
|---|---|---|---|
| checked | boolean | - | Estado actual, obligatorio. |
| onCheckedChange | (checked: boolean) => void | - | Recibe el estado siguiente, obligatorio. |
| id | string | - | Relaciona el botón con un Label externo. |
| disabled | boolean | false | Bloquea la interacción y reduce la opacidad. |
Cuándo sí y cuándo no
Hacé
- Controlá el estado y persistilo como lo requiere el formulario.
- Asociá un Label mediante id y htmlFor.
- Explicá por qué está deshabilitado.
Evitá
- No prometas un cambio guardado si el caller todavía no lo persistió.
- No inventes props como defaultChecked: este componente es controlado.
- No dependas solo del color para explicar el estado.
Accesibilidad
- Tab enfoca el botón; Espacio y Enter alternan el estado.
- role switch y aria-checked expresan el estado para lectores de pantalla.
- El Label externo aporta el nombre accesible; disabled saca el botón del recorrido de Tab.