diff --git a/skills/react-email/SKILL.md b/skills/react-email/SKILL.md index 57a62b03d..0b495e5bf 100644 --- a/skills/react-email/SKILL.md +++ b/skills/react-email/SKILL.md @@ -19,7 +19,7 @@ metadata: # React Email -Build and send HTML emails using React components - a modern, component-based approach to email development that works across all major email clients. +Build and send HTML emails using React components. A modern, component-based approach to email development that works across all major email clients. ## Installation @@ -355,12 +355,36 @@ See [references/PATTERNS.md](references/PATTERNS.md) for complete examples inclu 1. **Test across email clients** - Gmail, Outlook, Apple Mail, Yahoo Mail 2. **Keep it responsive** - Max-width around 600px, test on mobile -3. **Use absolute image URLs** - Host on reliable CDN, always include `alt` text -4. **Provide plain text version** - Required for accessibility -5. **Keep file size under 102KB** - Gmail clips larger emails -6. **Add proper TypeScript types** - Define interfaces for all email props -7. **Include preview props** - Add `.PreviewProps` for development testing -8. **Use verified domains** - For production `from` addresses +3. **Use absolute image URLs** - Host on reliable CDN +4. **Write meaningful alt text** - Describe purpose and details for content images; use `alt=""` for decorative images (spacers, dividers, background flourishes). React Email's `` defaults to `alt=""`. +5. **Provide plain text version** - Required for accessibility +6. **Keep file size under 102KB** - Gmail clips larger emails +7. **Add proper TypeScript types** - Define interfaces for all email props +8. **Include preview props** - Add `.PreviewProps` for development testing +9. **Use verified domains** - For production `from` addresses + +### Accessibility + +React Email handles the structural defaults; the rest is content. + +**What React Email gives you for free:** +- `` sets `lang` and `dir` (defaults: `lang="en" dir="ltr"` — override per locale) +- `` defaults to `alt=""` so decorative images are skipped by screen readers +- `` renders layout tables with `role="presentation"` +- `` also emits a `` tag + +Upgrade with `npm install react-email@latest` to get these defaults. + +**What you still have to do (content choices):** +- Open with a single `<Heading as="h1">`, nest subheadings in order, never skip levels (very short SMS-style emails may skip the heading entirely) +- Set descriptive `alt` on meaningful images; pass an explicit `alt=""` on decorative images — never omit the attribute +- **Linked images are never decorative.** When an `<Img>` is inside a `<Link>` or `<Button>`, the `alt` must describe where the link goes — `alt=""` on a linked image leaves the link with no accessible name +- Write link text that describes the destination (`<Button>Read the report</Button>`, not `click here`) +- Hit 4.5:1 text contrast (WCAG AA); preview in dark mode +- For layout tables you build by hand (outside `<Markdown>`), add `role="presentation"` +- For non-English emails, pass the locale: `<Html lang={locale} dir={isRTL ? 'rtl' : 'ltr'}>` (see [I18N.md](references/I18N.md)) + +For the full rule set, severity ranking, and authoring checklist, see the [accessibility reference](https://github.com/resend/email-best-practices/blob/main/references/accessibility.md) in the `email-best-practices` skill. ## Additional Resources diff --git a/skills/react-email/references/COMPONENTS.md b/skills/react-email/references/COMPONENTS.md index 80d3dccef..b905023df 100644 --- a/skills/react-email/references/COMPONENTS.md +++ b/skills/react-email/references/COMPONENTS.md @@ -155,6 +155,8 @@ import { Section } from 'react-email'; </Section> ``` +Layout components (`<Section>`, `<Row>`, `<Container>`, `<Markdown>` tables) render `<table role="presentation">` by default so screen readers don't announce them as data tables. If you drop in a raw `<table>` for layout, add `role="presentation"` yourself. + ### Row & Column Row displays content areas horizontally, Column displays content areas vertically. A Column needs to be used in combination with a Row component. @@ -286,13 +288,15 @@ import { Img } from 'react-email'; **Props:** - `src` (required) - Image URL (must be absolute) -- `alt` (required) - Alt text for accessibility +- `alt` - Alt text for accessibility (defaults to `""`; set a descriptive value for meaningful images) - `width` - Image width in pixels - `height` - Image height in pixels **Best practices:** - Always use absolute URLs hosted on CDN -- Always include alt text +- **Meaningful images**: write descriptive `alt` text covering purpose and key details (e.g., `alt="Red bicycle leaning against a brick wall"`, not `alt="image"`) +- **Decorative images** (spacers, dividers, background flourishes): pass an explicit `alt=""` so screen readers skip them cleanly — never omit the attribute +- **Linked images are never decorative.** When `<Img>` sits inside a `<Link>` or `<Button>`, its `alt` must describe where the link goes (e.g., `alt="View order #123"`). An empty `alt=""` on a linked image leaves the link with no accessible name for screen readers - Specify width and height to prevent layout shift - Use `block` class to avoid spacing issues diff --git a/skills/react-email/references/STYLING.md b/skills/react-email/references/STYLING.md index c15573154..044609f3b 100644 --- a/skills/react-email/references/STYLING.md +++ b/skills/react-email/references/STYLING.md @@ -153,14 +153,22 @@ Use consistent spacing that respects content hierarchy. Larger margins for headi - Never distort user-provided images - Never create SVG images - Always use absolute URLs -- Include `alt` text for accessibility +- Set descriptive `alt` text on meaningful images; pass an explicit `alt=""` on decorative images so screen readers skip them — never omit the attribute ```tsx +{/* Meaningful image — describe purpose and details */} <Img - src="https://example.com/image.png" - alt="Description" + src="https://example.com/hero.png" + alt="A team of engineers reviewing code on a laptop" className="w-full h-auto" /> + +{/* Decorative image — always pass an empty alt string so screen readers skip it */} +<Img + src="https://example.com/divider.png" + alt="" + className="w-full" +/> ``` ## Buttons