Editor Extensions & Commands
Relevant source files
The following files were used as context for generating this wiki page:- packages/editor/src/extensions/index.ts
- packages/editor/src/ui/bubble-menu/bubble-menu.tsx
- packages/editor/src/ui/slash-command/commands.tsx
- skills/react-email/references/EDITOR.md
- packages/editor/src/core/serializer/compose-react-email.spec.tsx
- packages/editor/package.json
- apps/web/src/app/editor/slash-commands/example.tsx
- packages/editor/src/plugins/email-theming/extension.spec.ts
The React Email Editor utilizes a modular extension system built on TipTap and ProseMirror to provide a visual rich-text editing experience optimized for email creation. These extensions define the behavior, styling, and serialization of email-ready components like buttons, columns, and headings. Commands provide the user interface mechanisms—such as slash menus and bubble toolbars—to manipulate these extensions.
The system ensures that every node and mark created within the editor corresponds to a valid React Email component through the composeReactEmail serialization process. This architecture allows developers to embed a visual builder that outputs responsive HTML and plain text without manual code intervention.
Extension Architecture
The editor architecture separates core logic, UI primitives, and email-specific extensions. The @react-email/editor/extensions entry point provides the StarterKit, which bundles over 35 extensions including basic formatting (bold, italic) and specialized email layouts (columns, buttons).
Core Extensions and Priorities
Extensions like Link are assigned higher priority (e.g., priority 1000) to ensure they wrap other marks correctly during rendering. This priority management prevents invalid HTML nesting in email clients.
The diagram shows the flow from editor configuration through the extension kit to final serialization.
Sources: skills/react-email/references/EDITOR.md:40-55, packages/editor/src/core/serializer/compose-react-email.spec.tsx:84-100
Key Extension Categories
| Extension Type | Purpose | Examples |
|---|---|---|
| Nodes | Block-level elements | Paragraph, Heading, Button, Column |
| Marks | Inline formatting | Bold, Italic, Link, Uppercase |
| Plugins | Global editor behavior | EmailTheming, StarterKit |
| Layouts | Multi-column structures | TwoColumns, ThreeColumns, FourColumns |
Sources: packages/editor/package.json:80-110, apps/web/src/app/editor/slash-commands/example.tsx:32-38
Slash Commands
Slash commands allow users to insert blocks by typing / within the editor. The SlashCommand component renders a searchable menu of SlashCommandItem objects.
Default Command Set
The system provides a defaultSlashCommands array categorized into Text and Layout blocks.
| ID | Title | Category | Description |
|---|---|---|---|
TEXT | Text | Text | Standard paragraph block |
H1 | Title | Text | Large heading |
BUTTON | Button | Layout | Styled link button |
TWO_COLUMNS | 2 Columns | Layout | Side-by-side content |
DIVIDER | Divider | Layout | Horizontal rule |
Sources: skills/react-email/references/EDITOR.md:162-180
Command Implementation Flow
When you select an item from the slash command menu, the editor executes a command chain.
The sequence illustrates the interaction between the user, the slash menu, and the underlying editor command chain.
Sources: apps/web/src/app/editor/slash-commands/example.tsx:18-30, packages/editor/src/ui/slash-command/commands.tsx
Bubble Menus
Bubble menus are floating toolbars that appear contextually based on the user's selection or cursor position. They provide immediate formatting options for specific nodes or marks.
Contextual Visibility Logic
The BubbleMenu primitive uses hideWhenActiveNodes and hideWhenActiveMarks props to prevent overlapping toolbars. For example, the standard text bubble menu hides when the cursor is on a link to allow the LinkDefault menu to show.
BubbleMenu: Appears on general text selection for formatting (Bold, Alignment).BubbleMenu.LinkDefault: Appears when the cursor focuses an existing link to edit the URL.BubbleMenu.ButtonDefault: Provides a form to update button text and destination.BubbleMenu.ImageDefault: Facilitates image URL updates.
Sources: packages/editor/src/ui/bubble-menu/bubble-menu.tsx:1-20, skills/react-email/references/EDITOR.md:130-150
Email Theming Plugin
The EmailTheming extension manages the visual styles applied during both editing and serialization. It resolves styles from a theme (e.g., 'basic' or 'minimal') and inlines them as CSS properties.
Theming Behavior
- Resolution: The plugin resolves theme-specific colors (e.g.,
#0670DBfor links) and typography. - Injection: It injects scoped style tags into the document head for the editor preview.
- Serialization: During
composeReactEmail, it ensures buttons havedisplay: inline-blockandbox-sizing: border-boxfor email client compatibility.
Sources: packages/editor/src/plugins/email-theming/extension.spec.ts:160-185, packages/editor/src/core/serializer/compose-react-email.spec.tsx:280-300
Custom Extensions
Developers can extend the editor by creating custom nodes via EmailNode.create or marks via EmailMark.create. These custom extensions must define a renderToReactEmail method to instruct the serializer how to convert the TipTap JSON into a React component.
const CustomNode = EmailNode.create({
name: 'customNode',
group: 'block',
renderToReactEmail({ children, style }) {
return <div style={style}>{children}</div>;
},
});
Sources: skills/react-email/references/EDITOR.md:252-270, packages/editor/src/core/serializer/email-node.ts
The combination of StarterKit extensions, SlashCommand menus, and contextual BubbleMenu components forms the foundation of the React Email visual editing system, ensuring that user actions translate directly into email-compliant code.