Files
2026-05-27 23:29:53 +01:00

3.1 KiB

email-layout

(no submodules)

Purpose

EmailLayout is the root VNode every email template wraps its body in. It emits a 100%-width <table> with a themed muted background, an inner max-width table centred horizontally, and an optional invisible preview-text block that surfaces a snippet in the recipient's inbox-list view (Gmail, Apple Mail, etc.) without appearing in the rendered body.

The table-in-table structure is the canonical email-layout idiom: full-width clients (Outlook on desktop) honour the inner <table>'s pixel max-width where most CSS would be stripped, while modern clients honour both and the result looks identical.

Features

  • Table-in-table structure with role="presentation" so screen readers treat the markup as layout, not tabular data.
  • Optional preview prop rendering an invisible snippet (display:none; max-height:0; overflow:hidden) the inbox list samples.
  • Themed background, font-family, font-size, line-height, and foreground colour applied to the outer table; themed border, border-radius, and max-width applied to the inner table.
  • Children rendered into the inner content cell at padding: theme.spacing.lg.

Usage: Basic

import { EmailLayout } from "@suaveplan/email-templates/components";
import { h, renderVNode } from "@suaveplan/email-templates/vnode";

renderVNode(EmailLayout({
  children: h("p", {}, "Hi Jane"),
}));

Usage: Advanced

Pass a custom theme and preview text for inbox-list snippet:

import { EmailLayout } from "@suaveplan/email-templates/components";
import { h, renderVNode } from "@suaveplan/email-templates/vnode";
import { createTheme } from "@suaveplan/email-templates/theme";

const theme = createTheme({ colors: { muted: "#0f172a", primary: "#22d3ee" } });

renderVNode(EmailLayout({
  theme,
  preview: "Your invoice for January",
  children: h("p", {}, "Body content"),
}));

API Reference

Prop Type Description
children EmailChildren? Body nodes rendered into the inner cell.
theme EmailTheme? Theme override; defaults to defaultTheme.
preview string? Hidden preview text for inbox-list snippet.
style StyleObject? Reserved for future use; current renderer ignores.

Implementation Notes

The preview block emits a <div> (not a <span> or <table>) because historically Outlook 2007 mis-handled display:none on inline elements inside tables. The empty-preview branch is exercised by the omits the preview block test to keep the conditional fully covered.

maxWidth lives on the inner table, not the outer one — the outer table spans the viewport's full width to paint the muted background edge-to-edge. The inner table's max-width: 600px is the standard email-design recommendation; Apple's HIG suggests this number to ensure single-column readability across watch / phone / mail-app contexts.