Botón neumórfico
Relieve suave que se hunde al presionar, con modo interruptor.
Código completo
Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.
"use client";
/**
* Botón neumórfico: relieve suave que se hunde al presionarlo.
*
* El neumorfismo solo funciona si el botón y su fondo son del mismo color. Si tu fondo no es #e0e5ec, define
* `--gcn-bg`, `--gcn-shadow` y `--gcn-highlight` en un contenedor (también `--gcn-text` y `--gcn-active`).
*
* <div style={{ background: "#e0e5ec", padding: 48 }}>
* <NeumorphicButton>Guardar cambios</NeumorphicButton>
* <NeumorphicButton shape="round" aria-label="Favorito">♥</NeumorphicButton>
* <NeumorphicButton toggle>Silenciar</NeumorphicButton>
* </div>
*/
import { useState, type ButtonHTMLAttributes } from "react";
export type NeumorphicButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
/** `pill` es el botón de texto; `round` es un botón circular para un icono. */
shape?: "pill" | "round";
/** Convierte el botón en un interruptor: queda hundido mientras está activo. */
toggle?: boolean;
};
const CSS = `
.gcn-btn { --gcn-ground: var(--gcn-bg, #e0e5ec); --gcn-dark: var(--gcn-shadow, #a3b1c6); --gcn-light: var(--gcn-highlight, #ffffff); --gcn-ink: var(--gcn-text, #475569); --gcn-accent: var(--gcn-active, #4f5bd5);
display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-height: 50px; padding: 0 30px; border: 0; border-radius: 999px;
background: var(--gcn-ground); color: var(--gcn-ink); font-family: inherit; font-size: 15px; font-weight: 600; line-height: 1; letter-spacing: .01em; cursor: pointer;
box-shadow: 9px 9px 18px var(--gcn-dark), -9px -9px 18px var(--gcn-light);
transition: box-shadow .22s cubic-bezier(.16, 1, .3, 1), color .22s, transform .22s cubic-bezier(.16, 1, .3, 1); }
.gcn-btn[data-shape="round"] { width: 56px; height: 56px; min-height: 0; padding: 0; }
.gcn-btn:hover { color: var(--gcn-accent); box-shadow: 6px 6px 12px var(--gcn-dark), -6px -6px 12px var(--gcn-light); }
.gcn-btn:active, .gcn-btn[aria-pressed="true"] { color: var(--gcn-accent); box-shadow: inset 6px 6px 12px var(--gcn-dark), inset -6px -6px 12px var(--gcn-light); transform: scale(.985); }
.gcn-btn:focus-visible { outline: 2px solid var(--gcn-accent); outline-offset: 5px; }
.gcn-btn:disabled { opacity: .5; cursor: not-allowed; box-shadow: 4px 4px 8px var(--gcn-dark), -4px -4px 8px var(--gcn-light); }
.gcn-btn svg { width: 20px; height: 20px; }
@media (prefers-reduced-motion: reduce) { .gcn-btn { transition: none; } }
`;
export function NeumorphicButton({ shape = "pill", toggle = false, className, onClick, children, ...props }: NeumorphicButtonProps) {
const [pressed, setPressed] = useState(false);
return (
<>
<style>{CSS}</style>
<button
type="button"
{...props}
className={["gcn-btn", className].filter(Boolean).join(" ")}
data-shape={shape}
aria-pressed={toggle ? pressed : undefined}
onClick={(event) => {
if (toggle) setPressed((value) => !value);
onClick?.(event);
}}
>
{children}
</button>
</>
);
}
Úsalo en tu proyecto
Instálalo con la CLI de shadcn.
npx shadcn@latest add https://www.gassierconsulting.com/r/boton-neumorficoEjemplo de uso de Botón neumórfico
Después de copiar neumorphic-button.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.
import { NeumorphicButton } from "./neumorphic-button";
export default function Ejemplo() {
return <NeumorphicButton />;
}Personaliza Botón neumórfico 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 |
|---|---|
--gcn-bg | #e0e5ec |
--gcn-shadow | #a3b1c6 |
--gcn-highlight | #ffffff |
--gcn-text | #475569 |
--gcn-active | #4f5bd5 |
Accesibilidad y rendimiento
El archivo tiene 62 líneas (3 KB) y no necesita @keyframes. Esto es lo que hace Botón neumórfico 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).
- Expone su estado a tecnologías de apoyo con atributos aria-*.
- Es un componente de cliente de Next.js: incluye la directiva "use client".
Acerca del producto
Un botón de relieve suave (neumorfismo): dos sombras, una clara y otra oscura, lo hacen parecer extruido del fondo y se invierten al presionarlo. Incluye forma redonda para iconos y modo interruptor que queda hundido mientras está activo.
Incluye
Un solo archivo React + TypeScript, con los estilos dentro. No usa Tailwind ni bibliotecas externas.
- Forma de píldora o redonda
- Modo interruptor con aria-pressed
- Colores y sombras en variables CSS
- Estados hover, activo, foco visible y deshabilitado
Cómo usarlo
Colócalo sobre un fondo del mismo color que el botón (por defecto #e0e5ec); si usas otro, define --gcn-bg, --gcn-shadow y --gcn-highlight en un contenedor.