Because the existing ones make you pick two: open source, a real visual editor, or a bundle you'd actually ship.
| Solution | Open Source | Framework Agnostic | Bundle Size | MJML Export | Visual Editor |
|---|---|---|---|---|---|
| Unlayer | ✗ Proprietary | ✓ | ~300 kB+ | ✗ | ✓ |
| GrapesJS | ✓ | ✓ | ~250 kB+ | ✗ Plugin | ✓ |
| MJML / React Email | ✓ | ✗ Code-first (React Email is React-only) | Varies | ✓ | ✗ Code-only |
| Mosaico | ✓ | ✗ Knockout.js | ~200 kB+ | ✗ | ✓ |
| Lit Pigeon | ✓ MIT | ✓ Web Components | ~69 kB gzipped* | ✓ Built-in | ✓ Drag & Drop |
* Initial JS of this site's playground (editor + core + Lit, gzipped). The TipTap rich-text engine (~140 kB gz) lazy-loads on first text edit. Other tools' sizes are their published editor bundles and vary by configuration.
A full email workflow — designing, importing, exporting, extending — with none of it locked behind a vendor.
A visual editor with a block palette, reordering, multi-column layouts, undo/redo, and live device previews.
Import existing MJML templates; export MJML or responsive HTML built for Gmail, Outlook, and Apple Mail.
Web components with Lit. First-party wrappers for React, Vue, Svelte, and Angular — or plain vanilla JS.
~7 kB document core + ~48 kB editor UI (gzipped). The rich-text engine lazy-loads on first text edit — this demo boots on ~69 kB of JS.
An MCP server lets Claude, Cursor, or any MCP client author and edit emails in the same document format you ship.
Extend the editor with custom blocks, toolbars, and behaviors — inspired by ProseMirror.
Modular by design — one document format, focused packages around it.
One import, one element, any framework.
import '@lit-pigeon/editor';
import { createDefaultDocument } from '@lit-pigeon/core';
const editor = document.querySelector('pigeon-editor');
editor.document = createDefaultDocument('My Email');
import { PigeonEditor } from '@lit-pigeon/react';
import { createDefaultDocument } from '@lit-pigeon/core';
const doc = createDefaultDocument('My Email');
export default function App() {
return <PigeonEditor document={doc} />;
}
import { PigeonEditorModule } from '@lit-pigeon/angular';
// In your module
@NgModule({ imports: [PigeonEditorModule] })
// In your template
<pigeon-editor [document]="doc"></pigeon-editor>