La sección hero es el espacio más decisivo de toda tu landing page. Los visitantes se forman una impresión en apenas 50 milisegundos, así que tu hero tiene que comunicar valor de inmediato. Esta guía te lleva de la mano para crear una sección hero lista para producción en React con Tailwind CSS v4 y Framer Motion, el mismo enfoque que se usa en decenas de landing pages SaaS de alta conversión.
Qué hace que un hero sea excelente
Antes de escribir una sola línea de JSX, conviene tener claro qué necesita lograr el componente:
- Titular, una propuesta de valor clara, de 6 a 10 palabras como máximo
- Subtítulo, 1 o 2 frases que amplían el titular y conectan con el problema del lector
- CTA principal, un único botón con una etiqueta orientada a la acción ("Empezar a crear", no "Enviar")
- CTA secundaria, opcional, de menor compromiso ("Ver ejemplos", "Ver demo")
- Prueba social, avatares, valoración con estrellas o un solo número ("Más de 4.200 equipos confían en nosotros")
- Badge, una píldora opcional de anuncio sobre el titular ("Nuevo: soporte para modo oscuro")
Estructura del componente
Empieza por la interfaz de TypeScript. Las props tipadas evitan errores en tiempo de ejecución y hacen que el componente se documente a sí mismo:
// HeroCentered.tsx
"use client";
import { motion } from "framer-motion";
import { ArrowRight } from "lucide-react";
interface HeroCenteredProps {
badge?: string;
title: string;
titleAccent?: string;
description: string;
ctaLabel: string;
ctaUrl: string;
ctaSecondaryLabel?: string;
ctaSecondaryUrl?: string;
socialProof?: {
avatars: string[]; // image URLs
count: number;
label: string;
};
}
La directiva "use client" es obligatoria porque Framer Motion utiliza APIs del navegador. En Next.js 15 todos los componentes son Server Components por defecto, así que tienes que activar el renderizado en el cliente de forma explícita.
Layout y theming
En lugar de fijar colores a fuego como bg-white o text-gray-900, usa propiedades personalizadas de CSS. Así el componente se adapta al tema: cambias un atributo data-theme en un elemento padre y toda la sección se repinta:
export default function HeroCentered({ title, titleAccent, description, ctaLabel, ctaUrl, badge }: HeroCenteredProps) {
return (
<section
style={{
position: "relative",
overflow: "hidden",
paddingTop: "var(--section-padding-y-lg)",
paddingBottom: "var(--section-padding-y-lg)",
background: "var(--color-background)",
minHeight: "85vh",
display: "flex",
alignItems: "center",
}}
>
<div
style={{
width: "100%",
maxWidth: "var(--container-max-width)",
margin: "0 auto",
padding: "0 var(--container-padding-x)",
}}
>
<div style={{ maxWidth: "720px", margin: "0 auto", textAlign: "center" }}>
{/* Content goes here */}
</div>
</div>
</section>
);
}
El token de CSS --section-padding-y-lg vale 8rem por defecto. --container-max-width es 1280px. Ambos están definidos de forma global y se heredan automáticamente.
Animaciones de entrada escalonadas con Framer Motion
Una entrada escalonada hace que el hero se sienta cuidado sin resultar molesto. Cada elemento aparece entre 60 y 80 ms después del anterior:
const EASE = [0.16, 1, 0.3, 1] as const; // custom spring-like cubic-bezier
// Badge
<motion.div
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, ease: EASE }}
>
<span style={{
padding: "0.5rem 1.25rem",
borderRadius: "var(--radius-full)",
border: "1px solid var(--color-accent-border)",
background: "var(--color-accent-subtle)",
color: "var(--color-foreground-muted)",
fontSize: "0.8125rem",
fontWeight: 500,
}}>
{badge}
</span>
</motion.div>
// Headline, starts 60ms after badge
<motion.h1
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.06, ease: EASE }}
style={{
fontSize: "clamp(2.5rem, 5vw, 4.5rem)",
fontWeight: 700,
lineHeight: 1.08,
letterSpacing: "-0.03em",
color: "var(--color-foreground)",
}}
>
{title}{" "}
<em style={{
fontStyle: "italic",
fontWeight: 400,
textDecoration: "underline",
textDecorationColor: "var(--color-accent)",
textDecorationThickness: "3px",
textUnderlineOffset: "6px",
}}>
{titleAccent}
</em>
</motion.h1>
// Description, starts 140ms after badge
<motion.p
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.14, ease: EASE }}
style={{
fontSize: "1.125rem",
lineHeight: 1.7,
color: "var(--color-foreground-muted)",
}}
>
{description}
</motion.p>
El clamp() aplicado al tamaño de fuente resuelve el escalado responsive sin necesidad de media queries: crece de forma lineal desde 2.5rem en móvil hasta 4.5rem en pantallas anchas.
Tratamientos de fondo
Hay tres técnicas que funcionan especialmente bien para los fondos de un hero:
1. Resplandor de acento
Un círculo difuminado y semitransparente en el color de acento aporta profundidad sin restar protagonismo al texto:
<div
aria-hidden
style={{
position: "absolute",
top: "-20%",
left: "50%",
transform: "translateX(-50%)",
width: "60vw",
height: "60vw",
maxWidth: "800px",
borderRadius: "50%",
background: "var(--color-accent)",
opacity: 0.06,
filter: "blur(100px)",
pointerEvents: "none",
}}
/>
El atributo aria-hidden oculta el elemento decorativo a los lectores de pantalla. Una opacidad de 0.06 resulta lo bastante sutil para funcionar con cualquier tema.
2. Cuadrícula de puntos
Una cuadrícula SVG de puntos repetidos añade textura:
<div
aria-hidden
style={{
position: "absolute",
inset: 0,
backgroundImage: "radial-gradient(circle, var(--color-border) 1px, transparent 1px)",
backgroundSize: "24px 24px",
opacity: 0.5,
maskImage: "radial-gradient(ellipse 70% 60% at 50% 50%, black, transparent)",
}}
/>
La maskImage desvanece la cuadrícula en los bordes para que no choque con la sección inferior.
3. Ruido sutil
Una textura de ruido de 200×200px como SVG en data URI aporta una sensación táctil premium:
background-image: url("data:image/svg+xml,...");
opacity: 0.03;
Botón de CTA
El botón principal usa el color de acento con una transición de hover suave:
<a
href={ctaUrl}
style={{
display: "inline-flex",
alignItems: "center",
gap: "8px",
padding: "0.875rem 2rem",
borderRadius: "var(--radius-full)",
background: "var(--color-accent)",
color: "var(--color-foreground)",
fontWeight: 600,
fontSize: "0.9375rem",
textDecoration: "none",
transition: "background var(--duration-normal) var(--ease-out)",
}}
onMouseEnter={(e) => {
(e.target as HTMLAnchorElement).style.background = "var(--color-accent-hover)";
}}
onMouseLeave={(e) => {
(e.target as HTMLAnchorElement).style.background = "var(--color-accent)";
}}
>
{ctaLabel}
<ArrowRight style={{ width: 16, height: 16 }} />
</a>
Checklist de accesibilidad
Antes de publicar, comprueba lo siguiente:
- El
<section>tiene un nombre accesible mediantearia-labelo un<h1>visible en su interior - Los enlaces de la CTA usan texto descriptivo (nada de "Haz clic aquí")
- Los elementos decorativos llevan
aria-hidden - El ratio de contraste cumple WCAG AA (4.5:1 para texto normal, 3:1 para texto grande)
- El componente respeta
prefers-reduced-motion:
import { useReducedMotion } from "framer-motion";
const shouldReduceMotion = useReducedMotion();
// Use duration: 0 when shouldReduceMotion is true
transition={{ duration: shouldReduceMotion ? 0 : 0.6, ease: EASE }}
Variantes de hero listas para usar
Crear un hero desde cero lleva tiempo, y la optimización de la tasa de conversión es un experimento que nunca termina. En vez de partir de cero, echa un vistazo al catálogo de heros de Incubator: incluye heros centrados, heros de layout dividido, fondos de vídeo a pantalla completa, heros con texto animado y mucho más, todos construidos con el mismo sistema de tokens CSS y los patrones de Framer Motion descritos arriba. Cada variante viene con props de TypeScript y datos de ejemplo, lista para integrarse en tu app de Next.js.
Relacionado en incubator
- Componentes de sección hero en React: explora todas las variantes de hero listas para usar.
- Ejemplos de animaciones al hacer scroll: patrones de entrada de hero construidos con Framer Motion.
- Galería de efectos hover: interacciones de botones y CTA para secciones hero.
- Componentes de CTA en React: secciones de llamada a la acción que combinan con los layouts de hero.
- Incubator frente a Aceternity UI: librerías de componentes animados comparadas lado a lado.