React
The editor mounts as a component in your tree. Your router, your providers and your auth context still wrap it, and its state flows back into React like any other component's.
PageKit — the self-hosted GrapesJS site builder, sold as source. Get early access
Embed a customizable visual email editor into your React or Next.js application. Let your users create responsive email templates with reusable blocks, custom components and MJML or HTML export — while your product keeps its own users, data and sending infrastructure.
26k+
GitHub stars on the editor core
1.4M+
npm downloads a month
100+
Plugins and presets on GJS.Market
BSD-3-Clause
Licence of the editor core
Not a hosted editor you rent, and not a template gallery. An editing layer you mount inside the application you already run.
The editor mounts as a component in your tree. Your router, your providers and your auth context still wrap it, and its state flows back into React like any other component's.
Your users assemble emails by picking blocks and editing text where it sits, instead of describing a layout to a developer or fighting table markup by hand.
Components, blocks, panels and commands are all yours to define. The parts of the editing experience that are specific to your product can be written by you.
Templates are saved through your own API to your own database, and sent by whichever provider you already pay for. Nothing here calls an editor service at runtime.
This canvas is a React component running on this page — no editor bundle, no iframe. Add a block, click any section to select it, retype the text in place, restyle it, reorder it, and switch the preview between desktop, tablet and mobile. Open the HTML tab to see the kind of markup an email builder hands back to your code.
Blocks
Add a section to the email.
Click a section to select it, then edit or restyle it
Selection
Nothing selected
Click a section in the canvas, or add one from the Blocks panel.
Nothing below loads until you ask for it: there is no iframe in this page's HTML, and only one demo is mounted at a time. These are public demos hosted by their authors.
The newsletter preset: email-safe blocks, a restricted style manager and table-based output. This is the closest thing to what your users would see.
A React email builder is a visual editor that runs inside a React application and lets users create and customise email templates without writing HTML email markup by hand. It is not a separate product your users log into: it is a component in your app, so the templates, the accounts that own them and the infrastructure that sends them all stay on your side.
What passes through it
The editor's job ends at producing markup. Everything before and after it is your application.
In every one of these, the alternative is a developer editing a template by hand each time someone in the business wants a change.
Let customers design their own transactional and lifecycle emails inside your product, on their own plan, without a support ticket.
Give sales and success teams a way to shape customer communications themselves, with the fields and merge tags your CRM already exposes.
Build reusable templates once and reference them from every automated workflow, instead of duplicating markup per campaign step.
Make composing an issue a design task rather than an HTML task, and let each publication keep its own look.
Assemble promotional sends and order-related emails from blocks that already know how to render a product, a price and a call to action.
Let non-technical teams own the email content in an internal admin surface, while the developers keep the components and guardrails.
It is the editing foundation, not the finished product. That distinction is the point: everything below is a hook you build on rather than a feature you accept as given.
A full editing canvas with selection, a component tree and a style manager — the parts that take longest to write and are hardest to get right.
Define component types with their own traits and their own markup, so the editor understands the objects your application already has.
Register your own blocks under your own categories and they appear in the block panel like any built-in one.
Configure the device widths users can switch between while editing, and preview each one without leaving the canvas.
Point the storage manager at your own endpoints. Loading and saving become ordinary requests against your API.
Email presets, block packs, asset managers and storage adapters already exist, so you are not implementing every layer yourself.
Panels, buttons and commands are configurable, and you can drive a headless instance from your own React interface instead.
The packages install from npm and ship in your bundle. There is no editor service to call at runtime and no per-seat editor account.
GrapesJS provides the visual editing layer. Your React application stays in control of users, data, storage and publishing — which is the whole argument for embedding an editor rather than sending people to someone else's.
Your React application
The editor
Your backend
Embedding an editor into someone else's product raises a different set of questions.
Both paths end in the same place. The only real difference is where the module is allowed to be evaluated.
React
Vite, CRA, Remix client route
@grapesjs/react
the published wrapper component
GrapesJS
the editing canvas
Email preset
email-safe blocks and styles
Render the component. There is nothing else to arrange.
GrapesJS React integrationNext.js
Pages or App Router
dynamic(..., { ssr: false })
the one extra line
React component
your editor wrapper
GrapesJS
browser only
Email preset
email-safe blocks and styles
Everything else — API routes, data fetching, auth — is unchanged.
GrapesJS Next.js integrationThe SSR boundary, once
GrapesJS reaches for window and document while it initialises, so it cannot be evaluated on the server. In Next.js that means importing your editor component through next/dynamic with ssr: false and giving it a loading skeleton. That is the entire Next.js-specific cost; the page around the editor can still be server-rendered, and its data can still come from getStaticProps, getServerSideProps or a server component.
Three packages and a component. Everything after this — storage, custom blocks, MJML — is covered further down the page.
npm install grapesjs @grapesjs/react grapesjs-preset-newsletterimport GjsEditor from '@grapesjs/react';
import newsletter from 'grapesjs-preset-newsletter';
import 'grapesjs/dist/css/grapes.min.css';
// A normal React component. The editor is a child of your tree, so your
// router, your auth context and your providers all still wrap it.
export default function EmailBuilder({ template, onSave }) {
return (
<GjsEditor
options={{
height: '100vh',
// Storage is wired to your own API further down this page.
storageManager: false,
plugins: [newsletter],
projectData: template,
}}
onEditor={(editor) => {
// Everything the user builds comes back out as plain data you can
// put straight into React state or POST to your backend.
editor.on('update', () => {
onSave({
html: editor.getHtml(),
css: editor.getCss(),
project: editor.getProjectData(),
});
});
}}
/>
);
}In Next.js, one dynamic import keeps the editor out of the server render:
// app/emails/page.tsx (or pages/emails.tsx)
import dynamic from 'next/dynamic';
// GrapesJS reaches for window/document as it initialises, so it can only run
// in the browser. In Next.js that means one dynamic import with ssr: false —
// this is the whole of the Next.js-specific work.
const EmailBuilder = dynamic(() => import('@/components/EmailBuilder'), {
ssr: false,
loading: () => <EditorSkeleton />,
});
export default function EmailsPage({ template }) {
return <EmailBuilder template={template} onSave={saveTemplate} />;
}Versions above were checked against the published packages on 2026-09-03: grapesjs 0.23.6 is BSD-3-Clause; @grapesjs/react is MIT.
These come from the editor core and its email presets, not from anything you have to write.
Users move sections around the email and drop new ones in from the block panel.
Text, images and buttons are edited where they sit, with the inline editor swappable for one you already license.
Rows, columns and sections, built out of the table markup email clients expect rather than modern layout CSS.
Switch between configured device widths while editing so a layout can be checked narrow before it is sent.
Component types you define, with their own traits and their own rendered markup.
A palette of ready sections your users assemble from, grouped into categories you name.
An asset manager for images, which plugins can point at your own storage or a media service you already use.
A command history, so experimenting with a design is not a one-way door.
MJML exists to make responsive email markup writable by hand. A visual builder on top of it means nobody has to. GrapesJS does not include MJML in its core — a plugin adds MJML components to the editor, so the project serialises to MJML rather than to plain HTML.
Where the compile happens
// pages/api/email/compile.ts
//
// mjml is a Node package — it parses and renders on the server, not in the
// browser. So the editor produces MJML in the client and this route turns it
// into the table-based HTML that email clients actually accept.
import mjml2html from 'mjml';
export default function handler(req, res) {
const { html, errors } = mjml2html(req.body.mjml, {
validationLevel: 'soft',
keepComments: false,
});
// MJML reports what it could not understand rather than failing silently.
if (errors.length) console.warn('[mjml]', errors);
res.status(200).json({ html });
}The compiler is a Node package, so compilation belongs on the server — in Next.js, an ordinary API route. The reverse direction is not symmetrical: arbitrary HTML does not convert cleanly back into MJML, so pick the format your workflow needs before you build on one.
The editor hands your code three different things, and a React application usually wants all three at different moments.
editor.getHtml() + getCss()
The rendered email, table-based and inline-styled when an email preset is active. This is what you pass to a sending provider.
with the MJML plugin
The source document, when your workflow is built around MJML. Compile it on the server to get the HTML you actually send.
editor.getProjectData()
The editable project. Store it so a user can reopen a template months later and it comes back exactly as they left it.
Rendered markup and editable project are different artefacts with different lifetimes. Store the JSON; regenerate the HTML.
This is where an embedded builder pulls ahead of a generic email tool: the blocks can know about your domain. A block is not a picture of a product card — it can look the product up.
Your application
Email builder
To be precise about what this is: an arbitrary React component is not converted into an email component. JSX renders a DOM tree, and email clients will not honour most of it. What you write is a GrapesJS component type whose toHTML emits email-safe markup and whose traits map onto a record your application owns. The wiring is yours; the editor supplies the place to put it.
Reduce repetitive design work by shipping the sections your product actually sends, rather than a generic set your users have to adapt every time.
Logo, wordmark and preheader text, locked to the layout your brand guidelines specify.
The one message the email exists to deliver, sized to survive a narrow viewport.
The workhorse section: a visual with a paragraph under or beside it.
A domain block wired to your catalogue rather than a placeholder someone fills in.
Tiers and figures rendered from your billing data, so a price change is not a template edit.
A repeatable list of points, laid out with tables so it survives Outlook.
A bulletproof button with the padding and fallbacks each client needs.
Address, preferences and unsubscribe — the parts compliance cares about, kept out of the user's hands.
A template is just a saved project document, so shipping a starter library means seeding rows and loading one as projectData when a user picks it. These are the categories most products end up needing:
Common starting points
These are layout categories, not products for sale. GJS.Market lists email presets, block packs and template managers — it does not sell ready-made email designs, and this page will not show you cards for products that do not exist.
Users switch device width while editing, and the canvas re-lays out at that width. Email widths are narrower than web ones: 600px has been the safe desktop maximum for years.
What users can change per width
A preview is a preview. It shows how the markup reflows, not how a specific client will render it — which is the next section.
Email clients implement HTML and CSS differently, and have done for twenty years. A visual builder standardises the authoring workflow; it does not make the clients agree with each other.
Strips the document head in several contexts, so styles that must survive have to be inline.
Renders through Word on Windows in some versions, which is why email markup is still table-based.
The most permissive of the four, and therefore the least useful as your only test.
Its own handling of media queries and classes; worth checking if it is meaningful in your audience.
Which is why this page will not tell you it works perfectly everywhere. Table-based output with inline styles is the most predictable starting point available, and production emails should still be tested in the clients your own recipients actually use.
Connect the editor to the backend and data model you already have. Your users, your authentication, your database, your permissions and your publishing workflow all stay exactly where they are.
The round trip
// The editor asks your API for a template and hands it back on save.
// Your users, your auth, your database, your permissions — unchanged.
const options = {
storageManager: {
type: 'remote',
autosave: true,
stepsBeforeSave: 5,
options: {
remote: {
urlStore: `/api/email-templates/${templateId}`,
urlLoad: `/api/email-templates/${templateId}`,
// Your existing session cookie is all the auth it needs.
fetchOptions: { credentials: 'include' },
},
},
},
};
// pages/api/email-templates/[id].ts — an ordinary Next.js route handler.
export default async function handler(req, res) {
const session = await getSession(req);
if (!session) return res.status(401).end();
if (req.method === 'POST') {
await db.emailTemplate.update({
where: { id: req.query.id, orgId: session.orgId },
data: { project: req.body },
});
return res.status(200).json({ ok: true });
}
const row = await db.emailTemplate.findFirst({
where: { id: req.query.id, orgId: session.orgId },
});
return res.status(200).json(row?.project ?? {});
}GJS.Market does not host your templates, store your data or send your email. It sells plugins for an editor you run yourself.
Customise the editing experience until it reads as a native part of your React application rather than a third-party panel bolted into it. There is no vendor branding to remove in the first place.
What the user sees
What you can change
The most thorough version is to run the editor headless and build the entire interface in React yourself, using the editor only for the canvas and the model.
It is a reasonable thing to consider, right up until the list of parts is written down. Every item below is something an email editor needs before it is usable — not a nice-to-have.
What an email editor is made of
Build everything yourself
Every row above
Start with GrapesJS
The editing foundation
Build your email product — not another editor from scratch. We are not going to put a number of saved months on that; how long it would take your team depends on your team.
Every listing below is a real product with a live page, and its name, price and thumbnail render straight from the catalogue — so nothing on this page can drift out of sync with what is actually for sale.
The layer this page is about: React interfaces built around the editor core, for teams who want the surrounding UI to be React rather than the stock panels.
Browse this categoryA React interface around the editor, for teams who would rather extend components than configure panels.
A React-oriented preset, useful as a starting point when the surrounding application is already React.
A complete React interface built on a familiar component library, for products that want the editor to match the rest of their UI.
Replace the default web blocks with email-safe ones and narrow the style manager to properties email clients honour. This is what makes the editor an email editor.
Browse this categoryAdds MJML components to the editor so the project serialises to MJML and compiles to responsive HTML on your server.
The email starting point: email-safe blocks, a narrowed style manager and table-based output.
An alternative email preset, worth comparing against the newsletter one before you commit to a block vocabulary.
Ready-made sections and a manager for saving and reloading templates, so your users are not assembling every email from primitives.
Browse this categoryA larger set of ready email sections, so your users assemble from finished pieces rather than from primitives.
Save, list and reload projects — the mechanics behind shipping a starter template library to your users.
For the moments a developer needs to see or hand-edit the markup a section produces.
Browse this categoryWire the storage manager to a backend without writing the adapter, if the one you use is already covered.
Browse this categoryImage upload and media management, pointed at services teams already run rather than at local files.
Browse this categoryGetting the finished markup out of the editor and into whatever comes next in your pipeline.
Browse this categoryFour combinations that map onto real requirements. Every listing shown is one that exists — there is no imaginary plugin filling a gap in a diagram.
A first version: visual editing, email-safe blocks, HTML out.
When your workflow is built around MJML and compiles server-side.
Customer-facing, with templates and assets in your own infrastructure.
Campaign volume: many templates, many images, many authors.
Prices come from the catalogue at build time.
Your customer opens the builder
A route in your app, behind your auth, on their plan. No second account, no second login.
They assemble a template
From blocks you defined, including ones that know about their data in your product.
It saves to your database
The project document goes through your API route and lands in a row that belongs to their organisation.
A campaign or workflow references it
Your automation picks the template by id — it does not need to know how the editor works.
Your backend renders and sends
Merge fields resolved at send time, markup handed to the provider you already pay for.
Customers get visual control over email content. You keep the product, the data and the delivery infrastructure.
The pattern repeats across products that otherwise have nothing in common.
Reusable customer communication templates, owned by the teams who send them.
Templates designed once and referenced from every step of an automated workflow.
Campaign composition as a visual task, with each publication keeping its own identity.
Promotional and order-related emails built from blocks that already know the catalogue.
One editor, many client brands, each seeing an interface that looks like their own.
The editor creates the email. Your infrastructure sends it. Keeping that line clear is what makes the rest of this architecture simple.
Stage 01
The user edits; the editor serialises what they built into a project document.
project JSONStage 02
Stores the project against the account that owns it, and renders it when something asks to send.
API routeStage 03
Merge fields resolved, markup produced — compiled from MJML if that is your format.
HTML / MJMLStage 04
Handed to whichever sending API you already use, with its own deliverability and analytics.
recipientExamples of providers teams hand it to
Named as examples of where the markup ends up, not as built-in integrations. Neither GrapesJS nor GJS.Market ships a connector for any of them; you call their SDK from your own backend, as you already do for the rest of your email.
This is an architectural trade-off, not a scoreboard. The right-hand column says "depends" honestly: hosted editors differ from each other and change their terms, and we are not going to invent a specific answer on their behalf.
| Capability | Self-hosted GrapesJS | Hosted email editor |
|---|---|---|
| React integration | Yes — @grapesjs/react wrapper | Depends on the vendor |
| Self-hosting | Yes — npm packages in your bundle | Depends on the vendor and plan |
| Data ownership | Yes — your database | Depends on the vendor |
| Custom components | Yes — your own component types | Depends on the vendor |
| Custom UI | Yes — panels or a headless instance | Depends on the vendor |
| Plugin ecosystem | Yes — 100+ on GJS.Market | Depends on the vendor |
| Your own backend | Yes — your API routes | Depends on the vendor |
| Core licence | BSD-3-Clause | Proprietary |
| Vendor lock-in | Lower — the project data is yours | Potentially higher |
GrapesJS column verified against grapesjs 0.23.6 and @grapesjs/react on 2026-09-03. For a comparison against a specific named vendor, with its published pricing, see the dedicated page.
Get help building a production-ready React email builder around your product requirements — your components, your data model, your storage and your sending provider.
Build a custom email builderSend a brief describing your stack, your data model and the output format you need, and you get a scoped proposal back.
Neighbouring pages that take the same editor in a different direction.
The format and delivery argument: MJML in, inlined table-based HTML out, handed to a provider you already pay for.
Read the guideThe template-library angle: managing, versioning and reusing designs across a team.
See templatesThe same editor from the marketer's side, where the gesture matters more than the API.
See the builderThe React wrapper for page building generally, not only email.
See the integrationStart with GrapesJS, integrate it into your React application, and extend the editor with the email plugins your product actually requires.
Install the packages, mount the component and have an email editor running in your app today.
Quick startPresets, block packs, storage adapters and asset integrations — real listings with live prices.
Browse pluginsA production integration around your components, your data model and your sending provider.
Build a custom email builder