Footer claymorfismo
Losa de plastilina con esquinas muy redondas, enlaces como pastillas blandas que rebotan y botón de subir.
Código completo
Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.
"use client";
import type { CSSProperties } from "react";
/** Footer claymorfismo: losa de plastilina con esquinas muy redondas, enlaces como pastillas blandas y botón de subir que rebota. React + TypeScript, sin dependencias. */
export type FooterArcillaGrupo = { title: string; links: { label: string; href?: string }[] };
export type FooterArcillaProps = {
brand?: string;
tagline?: string;
groups?: FooterArcillaGrupo[];
legal?: string;
className?: string;
style?: CSSProperties;
};
const CSS = `
.gcfar-root { box-sizing: border-box; container-type: inline-size; width: 100%; padding: 36px clamp(14px, 4cqi, 48px) 0; background: #fff0e6; color: #40284d; font: 700 15px/1.45 ui-rounded, "SF Pro Rounded", "Nunito", ui-sans-serif, system-ui, sans-serif; }
.gcfar-root *, .gcfar-root *::before, .gcfar-root *::after { box-sizing: border-box; }
.gcfar-root a, .gcfar-root button { -webkit-tap-highlight-color: transparent; }
.gcfar-root :focus-visible { outline: 3px solid #40284d; outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .gcfar-root *, .gcfar-root *::before, .gcfar-root *::after { animation: none !important; transition-duration: .01ms !important; } }
.gcfar-slab { position: relative; padding: clamp(24px, 5cqi, 56px); border-radius: 48px 48px 0 0; background: #ffc6b0; box-shadow: inset -10px -14px 26px rgba(190, 90, 60, .35), inset 10px 14px 26px rgba(255, 255, 255, .6), 0 -14px 30px -14px rgba(190, 90, 60, .35); }
.gcfar-grid { display: grid; grid-template-columns: 1.3fr repeat(3, 1fr); gap: 32px; }
.gcfar-brand { margin: 0 0 8px; font: 900 30px/1 ui-rounded, "SF Pro Rounded", "Nunito", ui-sans-serif, sans-serif; letter-spacing: -.03em; }
.gcfar-tag { margin: 0; max-width: 26ch; color: #6d3f43; font-weight: 600; }
.gcfar-title { margin: 0 0 12px; font-size: 14px; letter-spacing: .06em; text-transform: uppercase; color: #8a4a3f; }
.gcfar-list { margin: 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: 8px; }
.gcfar-link { display: inline-flex; align-items: center; min-height: 40px; padding: 0 16px; border-radius: 999px; color: inherit; text-decoration: none; background: #ffd9c9; box-shadow: inset -3px -4px 6px rgba(190, 90, 60, .3), inset 3px 4px 6px rgba(255, 255, 255, .7), 3px 5px 8px -3px rgba(190, 90, 60, .4); transition: transform .3s cubic-bezier(.34, 1.56, .64, 1); }
.gcfar-link:hover { transform: translateY(-3px) scale(1.05); }
.gcfar-link:active { transform: scale(.95); }
.gcfar-bottom { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-top: 36px; padding-top: 20px; border-top: 2px dashed rgba(64, 40, 77, .22); color: #6d3f43; font-size: 14px; }
.gcfar-up { display: grid; place-items: center; width: 52px; height: 52px; border: 0; border-radius: 50%; background: #ffb08a; color: #40284d; cursor: pointer; box-shadow: inset -4px -5px 8px rgba(160, 60, 10, .4), inset 4px 5px 8px rgba(255, 255, 255, .6), 4px 8px 12px -4px rgba(160, 60, 10, .5); transition: transform .35s cubic-bezier(.34, 1.56, .64, 1); }
.gcfar-up:hover { transform: translateY(-6px); }
.gcfar-up:active { transform: scale(.9); }
@container (max-width: 760px) { .gcfar-grid { grid-template-columns: 1fr 1fr; } .gcfar-grid > :first-child { grid-column: 1 / -1; } }
@container (max-width: 460px) { .gcfar-grid { grid-template-columns: 1fr; } }`;
const DEFAULT_GROUPS: FooterArcillaGrupo[] = [
{ title: "Producto", links: [{ label: "Funciones" }, { label: "Precios" }, { label: "Novedades" }] },
{ title: "Empresa", links: [{ label: "Nosotros" }, { label: "Contacto" }, { label: "Blog" }] },
{ title: "Ayuda", links: [{ label: "Guías" }, { label: "Estado" }, { label: "Privacidad" }] },
];
export function FooterArcilla({ brand = "Plastilina", tagline = "Herramientas amables para equipos pequeños que hacen cosas grandes.", groups = DEFAULT_GROUPS, legal = "© 2026 Plastilina. Hecho a mano.", className = "", style }: FooterArcillaProps) {
return (
<footer className={`gcfar-root ${className}`} style={style}>
<style>{CSS}</style>
<div className="gcfar-slab">
<div className="gcfar-grid">
<div>
<p className="gcfar-brand">{brand}</p>
<p className="gcfar-tag">{tagline}</p>
</div>
{groups.map((group) => (
<nav key={group.title} aria-label={group.title}>
<h3 className="gcfar-title">{group.title}</h3>
<ul className="gcfar-list">
{group.links.map((link) => (
<li key={link.label}>
<a className="gcfar-link" href={link.href ?? "#"} onClick={(event) => !link.href && event.preventDefault()}>
{link.label}
</a>
</li>
))}
</ul>
</nav>
))}
</div>
<div className="gcfar-bottom">
<span>{legal}</span>
<button className="gcfar-up" type="button" aria-label="Volver arriba" onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}>
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M12 19V5M5 12l7-7 7 7" />
</svg>
</button>
</div>
</div>
</footer>
);
}
Úsalo en tu proyecto
Instálalo con la CLI de shadcn.
npx shadcn@latest add https://www.gassierconsulting.com/r/footer-arcillaEjemplo de uso de Footer claymorfismo
Después de copiar footer-arcilla.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.
import { FooterArcilla } from "./footer-arcilla";
export default function Ejemplo() {
return <FooterArcilla brand="Ejemplo" />;
}Propiedades de FooterArcilla
FooterArcilla acepta 6 propiedades: todas son opcionales y tienen un valor por defecto, así que funciona sin configurar nada.
| Propiedad | Tipo | Descripción |
|---|---|---|
brand? | string | Opcional. |
tagline? | string | Opcional. |
groups? | FooterArcillaGrupo[] | Opcional. |
legal? | string | Opcional. |
className? | string | Opcional. |
style? | CSSProperties | Opcional. |
Accesibilidad y rendimiento
El archivo tiene 82 líneas (5 KB) y no necesita @keyframes. Esto es lo que hace Footer 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).
- Expone su estado a tecnologías de apoyo con atributos aria-*.
- Es un componente de cliente de Next.js: incluye la directiva "use client".