Ir al contenido
Evaluar mi proyecto
Componentes · HerosDisponible

Hero Material Design 3

Superficies tonales, forma que se transforma entre figuras, chips y botones con la tipografía y el movimiento de Material 3.

Gratis para equipos pequeñosSin tarjeta

Todo tu equipo, en la misma página

Tareas, calendario y archivos con la claridad de Material 3: superficies tonales, formas con carácter y movimiento con propósito.

Código completo

Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.

hero-material.tsx92 líneas
Descargar
"use client";

import type { CSSProperties } from "react";

/** Hero Material Design 3 expresivo: superficies tonales, forma que se transforma entre figuras, chips y botones con la tipografía y el movimiento de M3. React + TypeScript, sin dependencias. */
export type HeroMaterialProps = {
  title?: string;
  description?: string;
  primary?: string;
  secondary?: string;
  chips?: string[];
  href?: string;
  className?: string;
  style?: CSSProperties;
};

const CSS = `
.gchmt-root { box-sizing: border-box; position: relative; container-type: inline-size; width: 100%; min-height: 620px; overflow: hidden; color: #1d1b20; background: #fef7ff; font: 400 16px/24px Roboto, "Google Sans", ui-sans-serif, system-ui, sans-serif; letter-spacing: .5px; }
.gchmt-root *, .gchmt-root *::before, .gchmt-root *::after { box-sizing: border-box; }
.gchmt-root a { -webkit-tap-highlight-color: transparent; }
.gchmt-root :focus-visible { outline: 3px solid #1d1b20; outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .gchmt-root *, .gchmt-root *::before, .gchmt-root *::after { animation: none !important; transition-duration: .01ms !important; } }
.gchmt-grid { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 24px; align-items: center; min-height: 620px; padding: 48px clamp(20px, 5cqi, 64px); }
.gchmt-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 22px; }
.gchmt-chip { display: inline-flex; align-items: center; height: 32px; padding: 0 12px; border-radius: 8px; box-shadow: inset 0 0 0 1px #79747e; color: #49454f; font-size: 14px; font-weight: 500; letter-spacing: .1px; }
.gchmt-title { margin: 0 0 16px; font: 400 clamp(40px, 6.6cqi, 76px)/1.06 Roboto, "Google Sans", ui-sans-serif, sans-serif; letter-spacing: -.02em; text-wrap: balance; }
.gchmt-desc { margin: 0 0 32px; max-width: 44ch; color: #49454f; font-size: clamp(16px, 1.8cqi, 18px); text-wrap: pretty; }
.gchmt-actions { display: flex; flex-wrap: wrap; gap: 12px; }
.gchmt-btn { position: relative; overflow: hidden; display: inline-flex; align-items: center; height: 56px; padding: 0 28px; border-radius: 28px; font-weight: 500; font-size: 16px; letter-spacing: .1px; text-decoration: none; transition: box-shadow .2s, border-radius .25s cubic-bezier(.2, 0, 0, 1); }
.gchmt-btn::after { content: ""; position: absolute; inset: 0; background: currentColor; opacity: 0; transition: opacity .15s; }
.gchmt-btn:hover::after { opacity: .08; }
.gchmt-btn:active { border-radius: 14px; }
.gchmt-btn[data-p="true"] { background: #6750a4; color: #fff; }
.gchmt-btn[data-p="true"]:hover { box-shadow: 0 1px 3px 1px rgba(0, 0, 0, .15), 0 1px 2px rgba(0, 0, 0, .3); }
.gchmt-btn[data-p="false"] { background: #e8def8; color: #1d192b; }
.gchmt-art { position: relative; aspect-ratio: 1; width: 100%; max-width: 480px; justify-self: center; }
.gchmt-shape { position: absolute; inset: 4%; background: #eaddff; animation: gchmt-morph 9s cubic-bezier(.4, 0, .2, 1) infinite alternate; }
.gchmt-shape2 { position: absolute; inset: 24%; background: #6750a4; animation: gchmt-morph 7s cubic-bezier(.4, 0, .2, 1) -3s infinite alternate-reverse; display: grid; place-items: center; color: #fff; }
.gchmt-shape2 svg { width: 38%; height: 38%; }
.gchmt-card { position: absolute; padding: 14px 18px; border-radius: 16px; background: #fff; box-shadow: 0 1px 3px 1px rgba(0, 0, 0, .15), 0 1px 2px rgba(0, 0, 0, .3); font-size: 14px; line-height: 20px; letter-spacing: .25px; }
.gchmt-card b { display: block; font-size: 22px; line-height: 28px; font-weight: 400; letter-spacing: 0; }
.gchmt-c1 { left: -2%; top: 14%; animation: gchmt-bob 5s ease-in-out infinite; }
.gchmt-c2 { right: -2%; bottom: 12%; background: #ffd8e4; animation: gchmt-bob 6s ease-in-out -2s infinite; }
@container (max-width: 820px) { .gchmt-grid { grid-template-columns: minmax(0, 1fr); } .gchmt-art { max-width: 320px; } }
@keyframes gchmt-morph { 0% { border-radius: 50%; } 25% { border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; } 50% { border-radius: 26%; } 75% { border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%; } 100% { border-radius: 42% 58% 34% 66% / 50% 50% 50% 50%; } }
@keyframes gchmt-bob { 50% { transform: translateY(-10px); } }`;

export function HeroMaterial({ title = "Todo tu equipo, en la misma página", description = "Tareas, calendario y archivos con la claridad de Material 3: superficies tonales, formas con carácter y movimiento con propósito.", primary = "Crear espacio", secondary = "Ver el recorrido", chips = ["Gratis para equipos pequeños", "Sin tarjeta"], href = "#", className = "", style }: HeroMaterialProps) {
  return (
    <section className={`gchmt-root ${className}`} style={style}>
      <style>{CSS}</style>
      <div className="gchmt-grid">
        <div>
          <div className="gchmt-chips">
            {chips.map((chip) => (
              <span key={chip} className="gchmt-chip">
                {chip}
              </span>
            ))}
          </div>
          <h1 className="gchmt-title">{title}</h1>
          <p className="gchmt-desc">{description}</p>
          <div className="gchmt-actions">
            <a className="gchmt-btn" data-p="true" href={href}>
              {primary}
            </a>
            <a className="gchmt-btn" data-p="false" href={href}>
              {secondary}
            </a>
          </div>
        </div>
        <div className="gchmt-art" aria-hidden="true">
          <div className="gchmt-shape" />
          <div className="gchmt-shape2">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
              <path d="m4 12 5 5L20 6" />
            </svg>
          </div>
          <div className="gchmt-card gchmt-c1">
            <b>12 tareas</b>
            completadas hoy
          </div>
          <div className="gchmt-card gchmt-c2">
            <b>3 reuniones</b>
            esta semana
          </div>
        </div>
      </div>
    </section>
  );
}

Úsalo en tu proyecto

Instálalo con la CLI de shadcn.

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

Ejemplo de uso de Hero Material Design 3

Después de copiar hero-material.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.

ejemplo.tsx5 líneas
import { HeroMaterial } from "./hero-material";

export default function Ejemplo() {
  return <HeroMaterial title="Ejemplo" />;
}

Propiedades de HeroMaterial

HeroMaterial acepta 8 propiedades: todas son opcionales y tienen un valor por defecto, así que funciona sin configurar nada.

PropiedadTipoDescripción
title?stringOpcional.
description?stringOpcional.
primary?stringOpcional.
secondary?stringOpcional.
chips?string[]Opcional.
href?stringOpcional.
className?stringOpcional.
style?CSSPropertiesOpcional.

Accesibilidad y rendimiento

El archivo tiene 92 líneas (6 KB) y define 2 animaciones con @keyframes. Esto es lo que hace Hero Material Design 3 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 18 y 19 · Next.js (componente de cliente)