Ir al contenido
Evaluar mi proyecto
Componentes · BotonesDisponible

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.

neumorphic-button.tsx62 líneas
Descargar
"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.

terminal.sh1 líneas
npx shadcn@latest add https://www.gassierconsulting.com/r/boton-neumorfico

Ejemplo 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.

ejemplo.tsx5 líneas
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.

VariableValor 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".
Licencia
MIT
Dependencias
React >=18
Compatibilidad
React · Next.js (quita la directiva use client fuera de Next.js) · Sin Tailwind

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.