You need a complete editing foundation
Canvas, Blocks, Style Manager, Asset Manager, Layer Manager, commands and Storage are modules of the core rather than a backlog. If your roadmap currently contains four of those, that is the signal.
PageKit β the self-hosted GrapesJS site builder, sold as source. Get early access
Compare Craft.js and GrapesJS, understand the architectural differences, explore a live visual editor, and learn how to migrate a Craft.js-based editor to GrapesJS.
You own everything around the node tree.
The editing subsystems arrive assembled.
| Package | Version | License | Latest release | GitHub stars | npm downloads | |
|---|---|---|---|---|---|---|
| @craftjs/core | 0.2.12 | MIT | 2025-02-14 | 8,738 | 267k/mo | Source |
| grapesjs | 0.23.6 | BSD-3-Clause | 2026-08-25 | 26,188 | 1.4M/mo | Source |
Read from the npm registry and the GitHub API on 2026-09-03. Star counts and download figures are ecosystem signals, not a measure of which project suits your product. Both repositories are actively published and neither is archived.
GrapesJS and Craft.js solve related but different problems. Craft.js is a React-focused framework for building customizable page editors, while GrapesJS provides a broader visual editor foundation with components, blocks, styling, assets, storage and plugins.
GrapesJS can be a strong alternative when you want more editor infrastructure out of the box, especially for HTML/CSS-based visual editors, SaaS page builders, CMS editing surfaces and embeddable builders.
It is not universally better. If your product is deeply React-centric and the editor has to operate on a React component tree, Craft.js is the more direct fit β and the sections below say so in detail rather than as a disclaimer.
No scores, because the rows are not comparable quantities. Each capability is labelled with where it comes from: included in the project, reachable through an add-on, or defined by your own code.
| Capability | Craft.js | GrapesJS |
|---|---|---|
| Primary focus | A React framework for building your own page editors. | A visual editor framework with the editing surface already assembled. |
| React-first | Built-inYes. Components are React components; the tree is a React tree. | Add-onNo. The core is framework-agnostic; React arrives through @grapesjs/react. |
| Visual canvas | Built-inYour components render live and are directly selectable. | Built-inAn isolated canvas with direct selection and inline text editing. |
| Custom components | Built-inAny React component, described by a static Craft.js descriptor. | Built-inAny component type, described with a model, traits and defaults. |
| Drag and drop | Built-inIncluded. Connectors make an element draggable and droppable. | Built-inIncluded. Components move between containers on the canvas. |
| Drag-and-drop palette | CustomYou build the toolbox that lists what can be dragged in. | Built-inIncluded. Blocks register with the Block Manager and appear in a panel. |
| Style management | CustomApplication-defined. Styling is whatever your components already do. | Built-inIncluded. The Style Manager edits CSS per selector and per device. |
| Asset management | CustomApplication-defined. You supply your own media picker. | Built-inIncluded. The Asset Manager handles uploads and a media library. |
| Serialization | Built-inIncluded. The node tree serializes to JSON and loads back. | Built-inIncluded. Project data serializes to JSON and loads back. |
| Storage layer | CustomApplication-defined. You decide where the serialized JSON goes. | Built-inIncluded. The Storage Manager persists locally or to your endpoint. |
| Undo and redo | Built-inIncluded. An undo and redo history is part of the core API. | Built-inIncluded. The Undo Manager, with commands you can bind to a panel. |
| Layer tree panel | Add-onAn official add-on package renders the tree. | Built-inIncluded. The Layer Manager panel comes with the core. |
| Plugin architecture | CustomNo plugin system. You compose your own packages and the community's. | Built-inIncluded. A plugin is a function that receives the Editor and extends it. |
| Framework approach | React-focused by design. | Framework-agnostic core, integrated per framework. |
| HTML and CSS workflow | CustomApplication-defined. You render React and produce markup yourself. | Built-inNative. Clean HTML and CSS are the primary output. |
| SaaS page builders | Possible. You build the surrounding editing surface. | Strong fit. Most of that surface is already there. |
| White-label editors | Possible. The interface is yours from the first commit. | Strong fit. Panels, icons, labels and translations are all replaceable. |
Checked against both projects' own documentation on 2026-09-03: Craft.js 0.2.12 and GrapesJS 0.23.6. "Custom" is a description, not a criticism β for several rows it is exactly the reason a team chooses an unopinionated framework.
See what that means architecturallyThe biggest difference is not simply the number of features. The two frameworks give developers different starting points for building a visual editor.
A linear chain. Craft.js owns the node tree; every other layer is yours.
A chain with subsystems. The engine arrives with its own editing modules.
Craft.js starts lower. It gives you a node tree, drag-and-drop connectors, serialization and history, and it deliberately takes no position on styling, assets, storage or the panels around the canvas. That is a design decision, and for a team that wants to own its whole editing experience it is the right one.
GrapesJS starts higher. The canvas, the Blocks panel, the Style Manager, the Asset Manager, the Layer Manager, commands and the Storage Manager are modules of the core, and a plugin API exists to replace or extend any of them.
Neither framework is a platform. Neither one supplies hosting, accounts, permissions, billing, multi-tenancy or a publishing pipeline. Those sit outside both boxes and remain your responsibility either way.
So the question is not which project has more features. It is which starting point leaves you building the parts you actually want to own.
If the layers you would have to build sit above Craft.js in that first column, GrapesJS is worth evaluating. If they sit below it, migrating buys you very little.
Craft.js is a well-designed framework with a clear purpose, and several product shapes are simply a better match for it. These are not caveats β they are cases where choosing GrapesJS would be the wrong call.
If everything from routing to state to rendering already lives in React, an editor built from React primitives stays inside one mental model. Nothing has to cross a boundary.
Craft.js edits an actual React tree. If what your users are arranging is your React components β not markup β that correspondence is the whole value, and it is not something an HTML-first model reproduces.
Craft.js does not impose panels, toolbars or a settings surface. A team with strong design opinions gets a clean slate instead of something to override.
Memoization, context, suspense boundaries, render scheduling: when those details matter, keeping the editable tree inside React keeps them under your control.
A working editor with real users and real content is an asset. The cost of replacing it is rarely justified by a feature list alone.
If your resolver, your settings panels and your content pipeline all assume the Craft.js node model, that coupling is deep and reproducing it elsewhere is real work.
In these situations, replacing Craft.js may create unnecessary migration work.
See the full decision matrixThe signals below are about what you would otherwise have to build. Each card collects a few of them; if several describe your project, the evaluation is worth your time.
Canvas, Blocks, Style Manager, Asset Manager, Layer Manager, commands and Storage are modules of the core rather than a backlog. If your roadmap currently contains four of those, that is the signal.
GrapesJS edits a document and produces clean markup and stylesheets. When the artefact your users create has to be rendered outside your React app, that is a native workflow rather than an export step you write.
Your team's effort goes into accounts, plans, templates and publishing β not into rebuilding a style panel. GrapesJS is the editing layer inside that product, never the product itself.
SaaS page builder guideThe editor mounts into a DOM element that you control, inside an app you did not necessarily write. That constraint is what the embeddable guide is about.
Embeddable builder guidePanels, icons, labels, translations and the whole visual language are replaceable, so the editor can carry your customer's brand rather than yours.
White-label guideEmail demands table-based markup and inlined CSS β a different document model with the same editing surface. Presets exist for exactly that.
Email editor guideDon't just compare features. Try the editor yourself β drag a block in, select an element, restyle it, and switch the canvas to a phone width.
The official demo plus three published editors from the marketplace. Each one loads on click, in its own frame.
Open Full DemoThe stock GrapesJS editor with no plugins and no design system. This is what the core gives you before you configure anything.
Loads in a frame on this page.
Both projects call the thing a user drags around a "component", but the two definitions are not interchangeable. This is the difference that decides how much work a migration is.
A React component the editor drives through connectors. Its editable surface is its React props.
A definition in the editor's own document model. Its editable surface is traits, attributes and styles.
A React component with a Craft.js descriptor becomes a registered component type with a model and defaults. The markup it produces moves into that model.
Props that an editor user could change become traits. Props that only your code sets become attributes or fixed model properties.
The serialized node tree becomes project data. Both are JSON, but the shapes differ, so this is a transform you write and test.
Settings panels you wrote in React are replaced by the built-in trait panel, plus custom commands and panels where you need behaviour the core does not have.
This is a conceptual mapping, not an automatic converter. No tool reads a Craft.js resolver and emits GrapesJS component types β the correspondence above is what you implement, once per component type.
The same idea β a hero section with an editable heading and description β defined on each side. Read them as two definitions of one concept, not as a before and after of the same file.
// Craft.js: a component is a React component plus a `craft` descriptor.
// The editor drives it through connectors from useNode().
import { useNode } from '@craftjs/core';
export const Hero = ({ title, description }) => {
const { connectors: { connect, drag } } = useNode();
return (
<section ref={(ref) => connect(drag(ref))} className="hero">
<h1>{title}</h1>
<p>{description}</p>
</section>
);
};
Hero.craft = {
props: {
title: 'Build faster',
description: 'Create beautiful pages',
},
related: {
// The panel that edits those props is a React component you write.
settings: HeroSettings,
},
};// GrapesJS: a component type owns its markup and its editable traits.
// Traits are the closest analogue to Craft.js props.
editor.Components.addType('hero', {
model: {
defaults: {
tagName: 'section',
attributes: { class: 'hero' },
traits: [
{ name: 'title', type: 'text', changeProp: true },
{ name: 'description', type: 'text', changeProp: true },
],
components: [
{ tagName: 'h1', type: 'text', content: 'Build faster' },
{ tagName: 'p', type: 'text', content: 'Create beautiful pages' },
],
},
},
});
// A block is what makes the type draggable from the panel. Craft.js derives
// the equivalent from your toolbox; in GrapesJS it is a separate registration.
editor.Blocks.add('hero', {
label: 'Hero',
category: 'Sections',
content: { type: 'hero' },
});
// The trait panel edits those traits. You do not write it.Component definitions are only half of it. Everything your users already created is stored in the Craft.js node format, and moving it means walking that tree and emitting the definitions your new component types understand.
// Craft.js persists `query.serialize()` β a JSON map of nodes keyed by id,
// each with { type: { resolvedName }, props, nodes }. Migrating it means
// walking that map and emitting the GrapesJS component definitions your new
// types understand: a transform you write once, per component type.
const toGrapesJs = {
Hero: ({ title, description }) => ({ type: 'hero', title, description }),
// β¦one entry per resolver entry in your Craft.js editor
};
function craftNodeToGjs(nodes, id) {
const node = nodes[id];
const map = toGrapesJs[node.type.resolvedName];
if (!map) throw new Error(`Unmapped Craft.js component: ${node.type.resolvedName}`);
return {
...map(node.props),
components: (node.nodes ?? []).map((child) => craftNodeToGjs(nodes, child)),
};
}
const nodes = JSON.parse(craftSerializedJson);
editor.setComponents(craftNodeToGjs(nodes, 'ROOT').components);Both samples are illustrative. They show the shape of the mapping and the shape of the transform; neither is a drop-in migration, and nothing in either project generates one for you.
Three broad levels. None of them carries a duration, because the honest answer depends entirely on your codebase β and a page that promises you a number it cannot know is not helping you plan.
A handful of component types, a small settings surface, and content that has not accumulated many variations yet.
You are probably here if
Usually a relatively focused migration.
A real editor with its own panels, a template library, saved documents and a component set that has grown to fit the product.
You are probably here if
Requires component and data mapping.
Components that depend on app context, editor behaviour extended in non-obvious places, and business rules embedded in the editing experience.
You are probably here if
Requires an architecture review and a staged migration.
Migration complexity depends on how deeply the existing app is coupled to Craft.js.
Work through the checklistThe order a migration actually runs in, grouped into four phases. Useful whether you do it yourself or hand it to somebody.
15 stepsBefore anything is rebuilt, find out what actually has to move.
Component types, the palette, and the controls your users expect.
Existing content, where it is stored, and the media it references.
Prove it works, then move people over without a hard cutover.
The boxes are a printable plan, not saved state β nothing here is stored in your browser. Copy the steps into whatever tracker your team already uses.
Talk it through with someone who has done itNot automatically.
Craft.js and GrapesJS use different component and editor models. A Craft.js component is a React component the editor drives through connectors; a GrapesJS component type is a definition inside the editor's own document model. There is no adapter that turns one into the other, and any page that tells you otherwise is describing work you will discover later.
Take the markup and styling your React component produces and express it as a component type with traits. This is the default path and it is usually less work than it sounds, because the markup already exists.
Cost: One definition per component type, written by hand and reviewed like any other code.
Pricing rules, validation, data fetching and formatting rarely belong to the editor at all. Lift them into modules the editor calls, and they survive the move untouched.
Cost: Requires separating logic from rendering first, which is often worth doing regardless.
Some components really do need React at render time. Those can be rendered into a container the editor owns, with the editor treating the result as one component.
Cost: The most expensive option. Use it for the few components that need it, not as a general strategy.
The editable surface is what your users care about. Mapping each editable prop to a trait or attribute preserves the experience even when the implementation underneath is entirely new.
Cost: Property names and types have to be reconciled, and defaults have to be re-established.
One advantage of choosing GrapesJS is that you can extend the editor through plugins rather than implementing every feature from scratch. These are real listings from the GJS.Market catalogue β names, prices and images come straight from the marketplace, so nothing here can drift from what is actually for sale.
Checklist steps 1 to 5. Ready-made component and block sets you can start from instead of defining every type by hand.
Browse the sectionA baseline set of structural blocks to start the palette from.
Generates component types from existing markup.
Input components with editable properties, ready for the trait panel.
Lets your team register its own block set without writing the plumbing.
Checklist step 6. Inline rich text editing, which in a Craft.js project is almost always a component somebody on your team wrote.
Browse the sectionSwaps the built-in text editing for CKEditor 5.
Swaps the built-in text editing for TinyMCE 6.
Swaps the built-in text editing for Froala.
Extends the built-in text toolbar with more formatting actions.
If your React components are built on a utility or component framework, the same system can back the blocks your users drag in.
Browse the sectionTailwind-based blocks that match a utility-first design system.
Renders Tailwind classes inside the canvas.
Bootstrap 5 layout and content blocks.
Bootstrap 4 grid and content blocks for older systems.
Checklist steps 8 to 10. Where documents are persisted and where uploaded media goes.
Browse the sectionKeeps documents in the browser β useful for prototypes and offline work.
Persists project data to Cloud Firestore.
Stores uploaded media in Firebase.
Uses Cloudinary as the media library behind the Asset Manager.
Each of these is a different product, and each has its own guide with the architecture, the trade-offs and the plugins that apply.
Build a visual editor directly inside your SaaS product.
Read the guideEmbed a visual editor into an existing app.
Read the guideBuild React-based applications around GrapesJS.
Read the guideCreate visual email editing workflows with table-safe output.
Read the guideCreate a branded editing experience for your customers.
Read the guideAdd visual editing to a headless content system.
Read the guide@grapesjs/reactAn official wrapper component, or a plain ref and an effect.Next.jsnext/dynamicClient-only, loaded lazily so it stays out of the first payload.VueonMounted()Start it in the mounted hook, destroy it when the component unmounts.AngularngAfterViewInit()Start it after the view initialises, outside change detection.npm install grapesjs @grapesjs/reactimport grapesjs from 'grapesjs';
import GjsEditor from '@grapesjs/react';
import 'grapesjs/dist/css/grapes.min.css';
// GrapesJS owns an iframe canvas and touches `window`, so it mounts on the
// client. In Next.js, load this from a client component.
export default function VisualEditor() {
return (
<GjsEditor
grapesjs={grapesjs}
options={{
height: '100vh',
storageManager: { type: 'remote', autosave: true },
}}
onEditor={(editor) => {
// Register the component types you mapped from your Craft.js
// components here.
}}
/>
);
}The integration layer is thin on purpose. Your framework owns the page, GrapesJS owns the canvas, and your component types are registered once the editor exists.
If you have decided GrapesJS fits, there is still a second decision: carry the existing editor across, or build a new one beside it. They cost different things.
Carry the component set, the templates and the saved content across, and keep the product continuous for the people using it.
Choose migration when
More mapping work up front, far less disruption for the people who already rely on the editor.
See the checklistBuild the new editor as its own thing, take the content across once it is ready, and use the opportunity to fix what you would otherwise carry forward.
Consider starting fresh when
Less compatibility work, but the content transform still has to be written if documents already exist.
Try the editor firstOne requirement per row, one starting point. Four of these point at Craft.js, which is what makes the other five worth reading.
| Your requirement | Better starting point |
|---|---|
| An editor that operates on a React component tree | Craft.js |
| A complete visual editor foundation | GrapesJS |
| An HTML and CSS page builder | GrapesJS |
| A deeply React-first architecture | Craft.js |
| Built-in visual editing tools | GrapesJS |
| A highly custom React editor interface | Craft.js |
| A plugin-driven editor ecosystem | GrapesJS |
| A SaaS page builder | GrapesJS |
| An existing, mature Craft.js application | Assess the migration cost first |
There is no universal winner. The right choice depends on your editor architecture and product requirements.
GJS.Market builds and migrates GrapesJS editors. If you would rather not work through the checklist alone, these are the stages an engagement covers β and the first one is an assessment, which may well conclude that staying on Craft.js is the right answer.
Architecture assessment
We read the existing editor, work out how deeply it is coupled to Craft.js, and say plainly whether a migration is worth doing.
Component and template mapping
Each component type is mapped to a GrapesJS definition, with its editable properties turned into traits, and existing templates are mapped alongside them.
Data and asset migration
The transform from serialized Craft.js content to project data is written and tested against your real documents, and media is moved with it.
Custom editor logic and plugins
Behaviour that has no equivalent in the core is rebuilt as commands, panels or plugins, so it stays maintainable rather than patched in.
Storage and publishing
The Storage Manager is wired to your backend and the publishing path is connected end to end.
Parallel running and testing
Both editors run side by side against the same content so the new one can be verified before anyone is moved onto it.
It depends on what you are building. GrapesJS is the closest alternative for teams that want a visual editor foundation with components, blocks, styling, assets and storage already assembled. Puck is closer to Craft.js in spirit if you want to stay React-first. There is no single best answer, which is why this page is a comparison rather than a recommendation.
Not a drop-in one. The two have different component models, so moving means redefining your components and transforming your stored content. GrapesJS is a replacement in the sense that it can do the same job, not in the sense that you can swap the dependency.
Craft.js is a React framework for building page editors: it owns a node tree of your React components and leaves styling, assets, storage and the surrounding interface to you. GrapesJS is a visual editor framework whose core already includes a canvas, blocks, a Style Manager, an Asset Manager, a Layer Manager, commands, storage and a plugin system.
No. The core is framework-agnostic and has no React dependency. There is an official React wrapper package, but internally GrapesJS maintains its own document model rather than a React tree.
Yes. An official wrapper mounts the editor as a React component, and you can equally start it yourself from a ref and an effect. The React app hosts the editor; the editor still owns its own canvas.
Not automatically. A Craft.js component is a React component the editor drives through connectors; a GrapesJS component type is a definition in the editor's own model. Most teams rebuild the visual definition, keep the business logic in modules outside the editor, and add an integration layer only for the components that genuinely need React at render time.
Yes, by mapping them rather than converting them. Each Craft.js component becomes a registered component type, its editable props become traits, and the markup it rendered moves into the type's model. It is hand-written work, roughly one definition per component type.
Props an editor user can change map to traits. Props only your code sets map to attributes or fixed model properties. Application state that a component reads at render time has no direct equivalent and usually has to move out of the component and into the code around the editor.
Yes, once the component types exist. A template is stored content, so it goes through the same transform as any other document: walk the serialized node tree, emit the equivalent GrapesJS components, and save the result as a template in the new system.
Yes, with a transform you write. Craft.js persists a JSON map of nodes, each carrying a resolved component name, its props and its children. GrapesJS loads project data in its own JSON shape. Both are JSON, so the migration is a tree walk plus one mapping function per component type.
It is a common use for it. GrapesJS supplies the editing layer; accounts, plans, permissions, templates, hosting and publishing remain yours to build. The SaaS page builder guide covers how those responsibilities divide.
Yes. GrapesJS is client-only β it touches browser globals when it starts β so it is loaded lazily and rendered outside server rendering. That also keeps roughly 300 KB out of your first payload.
Yes. The package ships its own type definitions, so no separate types package is needed. The TypeScript guide covers the version floor and the types that are declared but not exported.
Yes. Panels, buttons, icons, labels and translations are all replaceable, and the plugin API can remove or rebuild parts of the interface entirely. That is what makes it viable as an editor embedded inside somebody else's branded product.
Yes. A plugin is a function that receives the Editor and registers component types, blocks, commands, panels or storage adapters. This is the main extension mechanism, and it is what the marketplace listings are built on.
GJS.Market is a catalogue of GrapesJS plugins, blocks, presets and integrations, organised by catalogue section. The plugins section of this page shows current listings with live prices.
Migrate when you have many templates, users who depend on the current editor, or business logic worth carrying across. Start fresh when the Craft.js editor is still small, there is little saved content, or the component architecture is changing anyway. Either way, existing documents still need a transform.
Yes. An engagement starts with an architecture assessment, then covers component and template mapping, data and asset migration, custom editor logic, storage and publishing, and a period of parallel running. The assessment can conclude that staying on Craft.js is the right answer.
If your current editor requires too much custom infrastructure, evaluate GrapesJS with a real project. Start with the editor, extend it with plugins, and customize the architecture around your product.
Use the editor running further up this page, then take the official demo and the marketplace demos for a longer run.
Open the editorComponents, blocks, rich text editing, design systems, storage and assets β extensions that replace work you would otherwise write.
Explore PluginsAn assessment first, then component mapping, data migration and parallel running. Including an honest answer if migrating is not worth it.
Request Migration Help