Componentes de React Email
@react-email/components incluye todos los componentes que necesitas para construir emails compatibles con cualquier cliente. Cada componente genera HTML optimizado con tablas y estilos inline por debajo, pero tú solo escribes JSX limpio.
Componentes de estructura
Estos componentes son la base de cualquier template:
Html, Head y Body
Obligatorios en todo template. Son el equivalente a <html>, <head> y <body>:
import { Html, Head, Body } from '@react-email/components'
export function MiEmail() {
return (
<Html>
<Head />
<Body style={{ backgroundColor: '#ffffff' }}>
{/* Contenido */}
</Body>
</Html>
)
}Container
Un div centrado con max-width. Funciona como el wrapper principal de tu contenido:
<Container style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}>
{/* Contenido centrado */}
</Container>Section
Agrupa contenido dentro del Container. Por debajo usa display: table para garantizar compatibilidad con clientes de email que no soportan flexbox:
<Section style={{ padding: '24px 0' }}>
<Text>Sección de contenido</Text>
</Section>Row y Column
Layout en columnas. Es el equivalente a un grid o flexbox pero compatible con email:
<Row>
<Column style={{ width: '50%' }}>
<Text>Columna izquierda</Text>
</Column>
<Column style={{ width: '50%' }}>
<Text>Columna derecha</Text>
</Column>
</Row>Componentes de contenido
Text
Párrafos de texto. Acepta cualquier estilo inline:
<Text style={{ fontSize: '16px', color: '#333' }}>
Este es un párrafo normal.
</Text>Heading
Encabezados de h1 a h6. Usa la prop as para definir el nivel:
<Heading as="h2" style={{ fontSize: '20px', color: '#111' }}>
Título de sección
</Heading>Link
Enlaces <a> con estilos:
<Link href="https://miapp.com/dashboard" style={{ color: '#0070f3' }}>
Ir al dashboard
</Link>Button
Un botón-enlace con estilos. Por debajo genera un <a> estilizado, no un <button> (los botones HTML no funcionan en emails):
<Button
href="https://miapp.com/confirmar"
style={{
backgroundColor: '#000',
color: '#fff',
padding: '12px 24px',
borderRadius: '6px',
textDecoration: 'none',
}}
>
Confirmar cuenta
</Button>Img
Imágenes con ancho y alto explicitos (importante para que no se deformen en diferentes clientes):
<Img
src="https://miapp.com/logo.png"
alt="Logo de Mi App"
width={150}
height={40}
/>Hr
Línea separadora:
<Hr style={{ borderColor: '#e6e6e6', margin: '20px 0' }} />Preview
Preview mejora la tasa de apertura
El componente Preview define el texto que aparece en la bandeja de entrada junto al asunto, antes de que el usuario abra el email. Es lo primero que ven tus usuarios, así que úsalo para dar contexto y aumentar engagement.
<Preview>Tu pedido #1234 fue enviado -- revisa los detalles</Preview>El texto de Preview no se muestra dentro del email, solo en la vista previa de la bandeja de entrada.
Font
Carga fuentes web. Ten en cuenta que solo funciona en algunos clientes (Apple Mail, iOS Mail). Gmail y Outlook usan fuentes del sistema:
<Font
fontFamily="Inter"
fallbackFontFamily="Arial"
webFont={{
url: 'https://fonts.googleapis.com/css2?family=Inter',
format: 'woff2',
}}
/>Ejemplo: template de factura
import {
Html,
Head,
Body,
Container,
Section,
Row,
Column,
Text,
Heading,
Hr,
Preview,
} from '@react-email/components'
interface InvoiceEmailProps {
nombreCliente: string
numeroFactura: string
items: { descripcion: string; cantidad: number; precio: number }[]
total: number
}
export function InvoiceEmail({
nombreCliente,
numeroFactura,
items,
total,
}: InvoiceEmailProps) {
return (
<Html>
<Head />
<Preview>Factura #{numeroFactura} -- Total: ${total} MXN</Preview>
<Body style={{ backgroundColor: '#f6f9fc', fontFamily: 'sans-serif' }}>
<Container style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}>
<Heading as="h1" style={{ fontSize: '24px', color: '#111' }}>
Factura #{numeroFactura}
</Heading>
<Text style={{ color: '#666' }}>Hola {nombreCliente},</Text>
<Text>Aquí tienes el detalle de tu compra:</Text>
<Section style={{ margin: '20px 0' }}>
<Row style={{ borderBottom: '1px solid #e6e6e6', padding: '8px 0' }}>
<Column style={{ width: '50%' }}>
<Text style={{ fontWeight: 'bold', margin: '0' }}>Descripción</Text>
</Column>
<Column style={{ width: '25%' }}>
<Text style={{ fontWeight: 'bold', margin: '0' }}>Cantidad</Text>
</Column>
<Column style={{ width: '25%' }}>
<Text style={{ fontWeight: 'bold', margin: '0' }}>Precio</Text>
</Column>
</Row>
{items.map((item, i) => (
<Row key={i} style={{ borderBottom: '1px solid #f0f0f0', padding: '8px 0' }}>
<Column style={{ width: '50%' }}>
<Text style={{ margin: '0' }}>{item.descripcion}</Text>
</Column>
<Column style={{ width: '25%' }}>
<Text style={{ margin: '0' }}>{item.cantidad}</Text>
</Column>
<Column style={{ width: '25%' }}>
<Text style={{ margin: '0' }}>${item.precio} MXN</Text>
</Column>
</Row>
))}
</Section>
<Hr />
<Text style={{ fontSize: '18px', fontWeight: 'bold' }}>
Total: ${total} MXN
</Text>
</Container>
</Body>
</Html>
)
}Ejemplo: reset de contraseña
import {
Html,
Head,
Body,
Container,
Text,
Button,
Hr,
Preview,
} from '@react-email/components'
interface ResetPasswordProps {
nombre: string
resetUrl: string
}
export function ResetPasswordEmail({ nombre, resetUrl }: ResetPasswordProps) {
return (
<Html>
<Head />
<Preview>Restablece tu contraseña</Preview>
<Body style={{ backgroundColor: '#f6f9fc', fontFamily: 'sans-serif' }}>
<Container style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}>
<Text style={{ fontSize: '20px', fontWeight: 'bold' }}>
Hola {nombre}
</Text>
<Text>
Recibimos una solicitud para restablecer la contraseña de tu cuenta.
Si no fuiste tú, ignora este email.
</Text>
<Button
href={resetUrl}
style={{
backgroundColor: '#000',
color: '#fff',
padding: '12px 24px',
borderRadius: '6px',
}}
>
Restablecer contraseña
</Button>
<Hr />
<Text style={{ color: '#666', fontSize: '12px' }}>
Este enlace expira en 1 hora. Si no solicitaste un cambio de
contraseña, puedes ignorar este email.
</Text>
</Container>
</Body>
</Html>
)
}Ejemplo: notificación simple
import {
Html,
Head,
Body,
Container,
Text,
Link,
Preview,
} from '@react-email/components'
interface NotificationProps {
mensaje: string
actionUrl: string
actionLabel: string
}
export function NotificationEmail({
mensaje,
actionUrl,
actionLabel,
}: NotificationProps) {
return (
<Html>
<Head />
<Preview>{mensaje}</Preview>
<Body style={{ backgroundColor: '#f6f9fc', fontFamily: 'sans-serif' }}>
<Container style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}>
<Text style={{ fontSize: '16px', color: '#333' }}>{mensaje}</Text>
<Link
href={actionUrl}
style={{ color: '#0070f3', textDecoration: 'underline' }}
>
{actionLabel}
</Link>
</Container>
</Body>
</Html>
)
}Estilos siempre como objetos inline
Todos los estilos en React Email deben ser objetos inline de React (la prop style con un objeto JavaScript). No uses strings CSS ni clases. Es la única forma de garantizar que los estilos funcionen en todos los clientes de email.