# Embed the React Email editor

> Add the open-source React Email visual editor to your own app: install it, mount the base editor, theme it, add the Inspector sidebar, and send the exported HTML with POST /emails.

The [React Email editor](https://react.email/docs/editor/overview) is an open-source visual editor that lets your users author email templates inside your own product. It ships with bubble menus, slash commands, an Inspector sidebar, and extensible nodes, and it exports email-ready HTML you can hand straight to MailBlastr. This guide covers embedding it in a React app, theming it, customizing the Inspector, and sending the result.

## Prerequisites

- A React 18+ application (Vite, Next.js, or Remix, for example).
- A bundler with [package exports](https://nodejs.org/api/packages.html#exports) support (the default for the frameworks above).

1. **Install the editor** — Add @react-email/editor and import the bundled theme stylesheet once at your app root.
2. **Mount the base editor** — The standalone EmailEditor component comes with the default extensions, menus, and theming wired up.
3. **Style the editor** — Override the --re-* CSS variables on a wrapper class to match your brand; the default theme also follows prefers-color-scheme and a .dark ancestor class.
4. **Add the Inspector sidebar** — Pass Inspector.Root as a child of EmailEditor so it shares the editor context and swaps panels based on the selection.
5. **Send the result with MailBlastr** — Read the exported HTML via the editor ref, POST it to your own server, and forward it to MailBlastr.

## Install

```bash
npm install @react-email/editor
```

**app/layout.tsx**

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

## Mount the base editor

**app/components/Editor.tsx**

```tsx
'use client';

import { EmailEditor } from '@react-email/editor';

const initialContent = `
  <h1>Welcome</h1>
  <p>Type "/" for a command, or select text to format it.</p>
`;

export function Editor() {
  return <EmailEditor content={initialContent} />;
}
```

`content` accepts an HTML string or a TipTap JSON document. For full control over which extensions load, drop down to the lower-level setup with `EditorProvider`.

## Theme it to your brand

The editor exposes two styling layers: the **chrome** (menus, palette, Inspector) driven by `--re-*` custom properties and `data-re-*` selectors, and the **content** area styled via TipTap’s `.tiptap` class. Override the variables on a wrapper class:

**app/styles/editor.css**

```css
.brand-editor {
  --re-bg: #fafaf9;
  --re-border: #d6d3d1;
  --re-text: #1c1917;
  --re-text-muted: #78716c;
  --re-hover: rgba(28, 25, 23, 0.04);
  --re-active: rgba(28, 25, 23, 0.08);
  --re-radius: 0.5rem;
}

[data-re-bubble-menu-item][data-active] {
  background: #2563eb;
  color: #fff;
}

.tiptap h1 {
  font-size: 1.75rem;
  letter-spacing: -0.025em;
}
```

## Add the Inspector sidebar

The Inspector is a contextual sidebar that swaps panels based on the current selection — document defaults, node properties, or text formatting. Pass `Inspector.Root` as a child of `EmailEditor` so it shares the editor context:

**app/components/Editor.tsx**

```tsx
'use client';

import { EmailEditor } from '@react-email/editor';
import { Inspector } from '@react-email/editor/ui';

export function Editor() {
  return (
    <div className="flex" style={{ height: '600px' }}>
      <EmailEditor
        content="<h1>Hello</h1><p>Click any element to inspect it.</p>"
        className="flex-1 min-w-0 overflow-y-auto p-4"
      >
        <Inspector.Root className="w-72 shrink-0 border-l p-4 overflow-y-auto">
          <Inspector.Breadcrumb />
          <Inspector.Document />
          <Inspector.Node />
          <Inspector.Text />
        </Inspector.Root>
      </EmailEditor>
    </div>
  );
}
```

## Send the exported HTML with MailBlastr

The standalone editor exposes its output through ref methods. Read the HTML in a handler, POST it to **your** server, and forward it to MailBlastr with [POST /emails](https://www.mailblastr.com/docs/api/emails-send) — never call MailBlastr from the browser, where your key would be exposed.

| Method | Returns | Description |
| --- | --- | --- |
| `getEmailHTML()` | `Promise<string>` | Email-ready HTML |
| `getEmailText()` | `Promise<string>` | Plain-text version |
| `getEmail()` | `Promise<{ html, text }>` | Both in one call |

```tsx
import { EmailEditor, type EmailEditorRef } from '@react-email/editor';
import { useRef } from 'react';

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

  const handleExport = async () => {
    if (!ref.current) return;
    const html = await ref.current.getEmailHTML();
    // Send via YOUR server-side endpoint — the key stays on the server.
    await fetch('/api/send-email', {
      method: 'POST',
      body: JSON.stringify({ html }),
    });
  };

  return (
    <div>
      <EmailEditor ref={ref} content="<p>Edit me</p>" />
      <button onClick={handleExport}>Export &amp; send</button>
    </div>
  );
}
```

**app/api/send-email/route.ts (your server)**

```ts
import { MailBlastr } from 'mailblastr';

const mb = new MailBlastr(process.env.MAILBLASTR_API_KEY);

export async function POST(req: Request) {
  const { html } = await req.json();

  const { data, error } = await mb.emails.send({
    from: 'Acme <hello@yourdomain.com>',
    to: ['customer@example.com'],
    subject: 'Your newsletter',
    html,
  });

  if (error) return Response.json(error, { status: 422 });
  return Response.json(data);
}
```

> **Note:** Want to store reusable templates centrally instead of exporting raw HTML each time? See [Template emails with React Email](https://www.mailblastr.com/docs/kb/react-email-templates) and the [Templates overview](https://www.mailblastr.com/docs/templates/overview).
