Interruptor claymorfismo
Pastilla de plastilina con bola que se estira al presionar y cambia a verde menta al activarse.
Código completo
Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.
"use client";
import { useState, type CSSProperties } from "react";
/** Interruptor claymorfismo: pastilla de plastilina que se estira al deslizar y cambia de color. React + TypeScript, sin dependencias. Personaliza con --gcicl-*. */
export type InterruptorArcillaProps = {
checked?: boolean;
defaultChecked?: boolean;
onChange?: (checked: boolean) => void;
label?: string;
disabled?: boolean;
className?: string;
style?: CSSProperties;
};
const CSS = `
.gcicl-root { box-sizing: border-box; display: inline-flex; align-items: center; gap: 16px; max-width: 100%; font: 800 16px/1.2 ui-rounded, "SF Pro Rounded", "Nunito", ui-sans-serif, system-ui, sans-serif; color: var(--gcicl-ink, #4a3566); }
.gcicl-root *, .gcicl-root *::before, .gcicl-root *::after { box-sizing: border-box; }
.gcicl-root button { font: inherit; -webkit-tap-highlight-color: transparent; }
.gcicl-root :focus-visible { outline: 3px solid #4a3566; outline-offset: 5px; border-radius: 999px; }
@media (prefers-reduced-motion: reduce) { .gcicl-root *, .gcicl-root *::before, .gcicl-root *::after { animation: none !important; transition-duration: .01ms !important; } }
.gcicl-sw { position: relative; width: 84px; height: 46px; padding: 0; border: 0; border-radius: 999px; cursor: pointer; background: var(--gcicl-off, #e4d9f5); box-shadow: inset 5px 6px 10px rgba(110, 80, 160, .3), inset -5px -6px 10px rgba(255, 255, 255, .8), 0 8px 14px -6px rgba(110, 80, 160, .35); transition: background .35s; }
.gcicl-sw[aria-checked="true"] { background: var(--gcicl-on, #7fe0b4); box-shadow: inset 5px 6px 10px rgba(10, 100, 60, .3), inset -5px -6px 10px rgba(255, 255, 255, .7), 0 8px 14px -6px rgba(20, 140, 90, .45); }
.gcicl-ball { position: absolute; top: 5px; left: 5px; width: 36px; height: 36px; border-radius: 999px; background: #fff7ee; box-shadow: inset -4px -5px 8px rgba(190, 140, 90, .4), inset 4px 5px 8px rgba(255, 255, 255, .9), 3px 6px 10px rgba(60, 30, 80, .3); transition: transform .45s cubic-bezier(.34, 1.56, .64, 1), width .25s; }
.gcicl-sw[aria-checked="true"] .gcicl-ball { transform: translateX(38px); }
.gcicl-sw:active:not(:disabled) .gcicl-ball { width: 46px; }
.gcicl-sw[aria-checked="true"]:active:not(:disabled) .gcicl-ball { transform: translateX(28px); }
.gcicl-sw:disabled { opacity: .5; cursor: not-allowed; }`;
export function InterruptorArcilla({ checked, defaultChecked = false, onChange, label = "Notificaciones", disabled, className = "", style }: InterruptorArcillaProps) {
const [inner, setInner] = useState(defaultChecked);
const on = checked ?? inner;
return (
<span className={`gcicl-root ${className}`} style={style}>
<style>{CSS}</style>
<button
className="gcicl-sw"
type="button"
role="switch"
aria-checked={on}
aria-label={label}
disabled={disabled}
onClick={() => {
setInner(!on);
onChange?.(!on);
}}
>
<span className="gcicl-ball" />
</button>
<span aria-hidden="true">{label}</span>
</span>
);
}
Úsalo en tu proyecto
Instálalo con la CLI de shadcn.
npx shadcn@latest add https://www.gassierconsulting.com/r/interruptor-arcillaEjemplo de uso de Interruptor claymorfismo
Después de copiar interruptor-arcilla.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.
import { InterruptorArcilla } from "./interruptor-arcilla";
export default function Ejemplo() {
return <InterruptorArcilla label="Ejemplo" checked />;
}Propiedades de InterruptorArcilla
InterruptorArcilla acepta 7 propiedades: todas son opcionales y tienen un valor por defecto, así que funciona sin configurar nada.
| Propiedad | Tipo | Descripción |
|---|---|---|
checked? | boolean | Opcional. |
defaultChecked? | boolean | Opcional. |
onChange? | (checked: boolean) => void | Opcional. |
label? | string | Opcional. |
disabled? | boolean | Opcional. |
className? | string | Opcional. |
style? | CSSProperties | Opcional. |
Personaliza Interruptor claymorfismo con variables CSS
Define estas variables en el contenedor o en tu hoja de estilos para cambiar los colores sin tocar el componente. Si no las defines, se usa el valor por defecto.
| Variable | Valor por defecto |
|---|---|
--gcicl-ink | #4a3566 |
--gcicl-off | #e4d9f5 |
--gcicl-on | #7fe0b4 |
Accesibilidad y rendimiento
El archivo tiene 54 líneas (3 KB) y no necesita @keyframes. Esto es lo que hace Interruptor claymorfismo por quien lo usa:
- Detecta prefers-reduced-motion y baja o quita el movimiento cuando la persona lo pide.
- Muestra un anillo de foco visible al navegar con teclado (:focus-visible).
- Declara roles ARIA para lectores de pantalla: switch.
- Es un componente de cliente de Next.js: incluye la directiva "use client".