All skills
resend avatar

/react-email

@e3ce28e official
by resendresend/resend-skills193 stars
28

Use when building HTML email templates with React components, adding a visual email editor to an application using the React Email visual editor, rendering emails to HTML, or sending emails with Resend. Covers welcome emails, password resets, notifications, order confirmations, newsletters, transactional emails, and the embeddable email editor component.

Use this Skill: https://skilld.dev/gh/resend/resend-skills/react-email

This session only. Nothing lands on disk.

referencesEDITOR.md

≈2.9k tokens on demand. Your agent reads this file only when SKILL.md points to it.

React Email Editor Reference

A visual rich-text editor for building email templates, built on TipTap and ProseMirror. Embed it in your app to let users compose email-ready HTML without writing code.

Table of Contents

Installation

Install the editor and its peer dependencies:

npm install @react-email/editor

Requires React 18+ and a bundler that supports package exports (Vite, Next.js, Webpack 5, etc.).

CSS Setup

Import the bundled default theme for the quickest start:

import '@react-email/editor/themes/default.css';

This includes the default color theme and built-in UI styles for bubble menus, slash commands, and the inspector.

To import only what you need:

import '@react-email/editor/styles/bubble-menu.css';
import '@react-email/editor/styles/slash-command.css';
import '@react-email/editor/styles/inspector.css';

Architecture

The editor is organized into six entry points:

Import Purpose
@react-email/editor EmailEditor: the all-in-one component
@react-email/editor/core composeReactEmail serialization, EmailNode, EmailMark, event bus, types
@react-email/editor/extensions StarterKit and 35+ email-aware extensions
@react-email/editor/ui BubbleMenu, SlashCommand, Inspector
@react-email/editor/plugins EmailTheming plugin
@react-email/editor/utils Attribute helpers, style utilities

EmailEditor Component

The EmailEditor component from @react-email/editor is a batteries-included component that bundles StarterKit, EmailTheming, BubbleMenus, and SlashCommands. Use it when you want the full experience with minimal setup.

import { EmailEditor, type EmailEditorRef } from '@react-email/editor';
import '@react-email/editor/themes/default.css';
import { useRef } from 'react';

export function MyEditor() {
  const editorRef = useRef<EmailEditorRef>(null);

  const handleExport = async () => {
    const { html, text } = await editorRef.current!.export();
    console.log(html, text);
  };

  return (
    <div>
      <EmailEditor
        ref={editorRef}
        content="<p>Start typing...</p>"
        theme="basic"
        onReady={(editor) => console.log('Editor ready', editor)}
        onChange={(editor) => console.log('Content changed')}
      />
      <button onClick={handleExport}>Export HTML</button>
    </div>
  );
}

Props

Prop Type Default Description
content Content — Initial editor content (HTML string or TipTap JSON)
onChange (editor: Editor) => void — Called on every content change
onUploadImage UploadImageHandler — Handler for pasted/dropped images
onReady (editor: Editor) => void — Called when editor is initialized
theme 'basic' | 'minimal' 'basic' Built-in email theme
editable boolean true Whether content is editable
placeholder string — Placeholder text for empty editor
bubbleMenu { hideWhenActiveNodes?: string[], hideWhenActiveMarks?: string[] } — Configure bubble menu visibility
extensions Extensions — Override the default extensions entirely
className string — CSS class for the editor container

Ref Methods (EmailEditorRef)

Method Returns Description
export() Promise<{ html: string; text: string }> Export email-ready HTML and plain text
getJSON() JSONContent Get editor content as TipTap JSON
getHTML() string Get editor content as HTML
editor Editor | null Access the underlying TipTap editor instance

Minimal Setup (Extensions Only)

For more control, use EditorProvider from @tiptap/react directly with StarterKit:

import { StarterKit } from '@react-email/editor/extensions';
import { EditorProvider } from '@tiptap/react';

const extensions = [StarterKit];

const content = {
  type: 'doc',
  content: [
    {
      type: 'paragraph',
      content: [{ type: 'text', text: 'Start typing or edit this text.' }],
    },
  ],
};

export function MyEditor() {
  return <EditorProvider extensions={extensions} content={content} />;
}

This gives you a content-editable area with all core extensions (paragraphs, headings, lists, tables, code blocks, columns, buttons, etc.) but no UI overlays.

Bubble Menus

Floating formatting toolbars that appear on text selection. Add as children of EditorProvider.

import { StarterKit } from '@react-email/editor/extensions';
import { BubbleMenu } from '@react-email/editor/ui';
import { EditorProvider } from '@tiptap/react';
import '@react-email/editor/themes/default.css';

const extensions = [StarterKit];

export function MyEditor() {
  return (
    <EditorProvider extensions={extensions} content={content}>
      <BubbleMenu />
    </EditorProvider>
  );
}

Available Bubble Menus

Component Appears when... Controls
BubbleMenu Text is selected Bold, italic, underline, strike, code, uppercase, alignment, node type, link
BubbleMenu.LinkDefault Cursor is on a link Edit URL, open link, unlink
BubbleMenu.ButtonDefault Cursor is on a button Edit button URL, unlink
BubbleMenu.ImageDefault Cursor is on an image Edit image URL

Exclude specific items from the default menu:

<BubbleMenu excludeItems={['strike', 'code', 'uppercase']} />

When combining the text bubble menu with contextual menus for links, images, or buttons, use hideWhenActiveMarks on BubbleMenu to prevent it from appearing when a link is focused.

Slash Commands

Insert content blocks by typing / in the editor.

import { defaultSlashCommands, SlashCommand } from '@react-email/editor/ui';

<EditorProvider extensions={extensions} content={content}>
  <SlashCommand items={defaultSlashCommands} />
</EditorProvider>

Default Commands

Command Category Description
TEXT Text Plain text block
H1, H2, H3 Text Headings
BULLET_LIST Text Unordered list
NUMBERED_LIST Text Ordered list
QUOTE Text Block quote
CODE Text Code snippet
BUTTON Layout Clickable button
DIVIDER Layout Horizontal separator
SECTION Layout Content section
TWO_COLUMNS Layout Two column layout
THREE_COLUMNS Layout Three column layout
FOUR_COLUMNS Layout Four column layout

Cherry-pick individual commands:

import { BUTTON, H1, H2, TEXT } from '@react-email/editor/ui';

<SlashCommand items={[TEXT, H1, H2, BUTTON]} />

Inspector

A contextual sidebar for editing document-level styles, node properties, and text formatting. Requires the EmailTheming plugin.

import { StarterKit } from '@react-email/editor/extensions';
import { EmailTheming } from '@react-email/editor/plugins';
import { Inspector } from '@react-email/editor/ui';
import { EditorContent, EditorContext, useEditor } from '@tiptap/react';
import '@react-email/editor/themes/default.css';

const extensions = [StarterKit, EmailTheming];

export function MyEditor() {
  const editor = useEditor({ extensions, content });

  return (
    <EditorContext.Provider value={{ editor }}>
      <div style={{ display: 'flex' }}>
        <div style={{ flex: 1 }}>
          <EditorContent editor={editor} />
        </div>
        <Inspector.Root style={{ width: 240, borderLeft: '1px solid #e5e7eb', padding: 16 }}>
          <Inspector.Breadcrumb />
          <Inspector.Document />
          <Inspector.Node />
          <Inspector.Text />
        </Inspector.Root>
      </div>
    </EditorContext.Provider>
  );
}

The inspector automatically switches between document, node, and text controls based on the current selection.

Email Theming

Apply visual styles (typography, spacing, colors) to email output. Themes are resolved during composeReactEmail and inlined as style attributes.

import { StarterKit } from '@react-email/editor/extensions';
import { EmailTheming } from '@react-email/editor/plugins';

const extensions = [StarterKit, EmailTheming.configure({ theme: 'basic' })];

Built-in Themes

Theme Description
'basic' Full styling: typography, spacing, borders, visual hierarchy. Default.
'minimal' Essentially no styles — blank slate for custom themes.

Switching Themes Dynamically

const [theme, setTheme] = useState<'basic' | 'minimal'>('basic');
const extensions = [StarterKit, EmailTheming.configure({ theme })];

// Re-key EditorProvider when theme changes
<EditorProvider key={theme} extensions={extensions} content={content}>

Email Export

Convert editor content to email-ready HTML and plain text.

Via EmailEditor ref

const editorRef = useRef<EmailEditorRef>(null);

const { html, text } = await editorRef.current!.export();

Via composeReactEmail (lower-level)

import { composeReactEmail } from '@react-email/editor/core';
import { useCurrentEditor } from '@tiptap/react';

function ExportPanel() {
  const { editor } = useCurrentEditor();

  const handleExport = async () => {
    if (!editor) return;
    const { html, text } = await composeReactEmail({
      editor,
      preview: 'Inbox preview text', // optional
    });
    console.log(html, text);
  };

  return <button onClick={handleExport}>Export HTML</button>;
}

The preview parameter is optional — when provided, it sets the inbox preview text in the exported HTML.

The export pipeline:

  1. Reads the editor's JSON document
  2. Traverses each node and mark
  3. Calls renderToReactEmail() on each EmailNode and EmailMark
  4. Applies theme styles via EmailTheming plugin (if configured)
  5. Wraps in a base template and renders to HTML string + plain text

Custom Extensions

Create custom email-compatible nodes using EmailNode (extends TipTap's Node with renderToReactEmail()):

import { EmailNode } from '@react-email/editor/core';
import { mergeAttributes } from '@tiptap/core';

const Callout = EmailNode.create({
  name: 'callout',
  group: 'block',
  content: 'inline*',

  parseHTML() {
    return [{ tag: 'div[data-callout]' }];
  },

  renderHTML({ HTMLAttributes }) {
    return [
      'div',
      mergeAttributes(HTMLAttributes, {
        'data-callout': '',
        style: 'padding: 12px 16px; background: #f4f4f5; border-left: 3px solid #1c1c1c;',
      }),
      0,
    ];
  },

  renderToReactEmail({ children, style }) {
    return (
      <div style={{ ...style, padding: '12px 16px', backgroundColor: '#f4f4f5', borderLeft: '3px solid #1c1c1c' }}>
        {children}
      </div>
    );
  },
});

// Register it
const extensions = [StarterKit, Callout];

For custom marks (inline formatting), use EmailMark from @react-email/editor/core — same pattern but for inline elements.

Source: SKILL.md on GitHub

No alerts17d4 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill provides a suite of components and guidelines for building, rendering, and sending responsive HTML emails using React and Tailwind CSS. It includes support for a visual editor, internationalization, and integration with various email service providers. No security issues were detected.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    1 finding · Score: 86/100

Signed by skilld at e3ce28e. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Activeupdated 3 months ago
Other metadata
metadata
{
  "author": "Resend",
  "version": "2.1.0",
  "homepage": "https://react.email",
  "source": "https://github.com/resend/react-email",
  "openclaw": {
    "install": [
      {
        "kind": "node",
        "package": "react-email",
        "label": "React Email"
      }
    ],
    "links": {
      "repository": "https://github.com/resend/react-email",
      "documentation": "https://resend.com/docs/react-email-skill"
    }
  }
}

README badge

README badge for resend/resend-skills/react-email

Build and send HTML emails using React components with a modern, component-based approach that works across all major email clients. Includes a dev preview server, Tailwind styling support, and an optional embeddable visual editor for email templates.

Generated from the current SKILL.md.

Does this work with TypeScript?
Yes. React Email is built for TypeScript and the skill examples use typed component props with interfaces. Make sure your tsconfig.json includes proper JSX support.
Can I use this with email services other than Resend?
Yes. React Email renders to HTML or plain text that works with any email service provider (Nodemailer, SendGrid, etc.). The skill includes examples for multiple providers.
What about responsive design and media queries?
Media queries are not reliably supported by email clients. The skill recommends using fixed layouts with max-width constraints and the Row/Column components instead of flexbox or grid.
Can I embed a visual editor in my application?
Yes. The skill includes the `@react-email/editor` component, a TipTap-based visual editor that can be embedded in your app and exports to email-ready HTML.
How do I handle static images like logos?
Place images in a `static` folder within your emails directory. Use environment-based URLs to switch between the dev server and production CDN in the same component.

Generated from the current SKILL.md. These answers refresh after source changes.