Craft.js review: build your own React page editor
Craft.js is an MIT-licensed React framework for building your own page editor: it supplies the drag-and-drop layer, node tree and state management, and leaves the entire editor UI to you. First published to npm in December 2019.
TL;DR
- Craft.js is an MIT-licensed React framework for building page editors: it supplies the node tree, drag-and-drop and state management, and leaves the entire editor interface to you.
- We measured @craftjs/core 0.2.12 at 29.2 kB gzip, the smallest bundle in this dataset and roughly a tenth of GrapesJS, because it ships no editor UI at all.
- It took 21 lines of application code to reach a working editor in our benchmark — the most of any library we tested — and that ordering is the whole story: the less a library gives you, the more you write.
Craft.js quick facts
| Type | Library |
|---|---|
| Licence | MIT |
| First release | 2019-12 |
| Language | TypeScript |
| Frameworks | React |
| SSR support | partial |
| Bundle size (min+gzip) | 29.2 kB gzip |
| Pricing | Free (open source) |
| Self-hosted | Yes |
| White label | Yes |
| npm weekly downloads | 64,907 |
| GitHub stars | pending sync |
| Latest version | 0.2.12 |
| Last verified | 2026-08-19 |
What Craft.js is, and who it is for
Craft.js is the most honest library in this dataset about what it does not do. It gives you a node tree, drag-and-drop behaviour, selection state and serialisation. It gives you no panels, no toolbar, no settings sidebar, no layer tree UI and no blocks. Those are your components, written by you, using Craft.js hooks.
That sounds like a disadvantage until you have shipped a product where the editor is embedded in an application with a strong visual identity. Every other option in this category either imposes an interface you must override, or hands you a hosted UI you cannot change. Craft.js starts from nothing, which means there is nothing to fight.
It is the right choice when the editing experience is a differentiator, when the editor is narrow and opinionated — a form builder, a dashboard composer, an email layout tool constrained to your templates — and when you have the engineering time. It is the wrong choice on a deadline.
Architecture: a tree, and hooks into it
The model is small enough to describe completely. Everything on the canvas is a node. A node has a
type (one of your React components), props, and a place in the tree. Two hooks connect your
components to it: useNode gives a component access to its own node — its props, its connectors,
whether it is selected — and useEditor gives any component access to the editor as a whole.
Connectors are the clever part. connect marks a DOM element as the node's rendered output;
drag marks it as a drag handle. A component becomes draggable and selectable by attaching a ref.
Rules on a node type control what may be dropped into it, which is how you enforce structure.
State serialises to JSON that you store. Because the node types are your components, the stored document has the same portability characteristics as Puck's: it means everything inside your app and nothing outside it.
Getting started
From our benchmark, and note how much of it is defining components rather than configuring an editor — that ratio is the library's defining feature.
import { createRoot } from 'react-dom/client';
import { Editor, Frame, Element, useNode } from '@craftjs/core';
function Heading({ text }) {
const { connectors: { connect, drag } } = useNode();
return <h1 ref={(ref) => connect(drag(ref))}>{text}</h1>;
}
Heading.craft = { displayName: 'Heading' };
function Container({ children }) {
const { connectors: { connect } } = useNode();
return <div ref={(ref) => connect(ref)} style={{ padding: 16 }}>{children}</div>;
}
Container.craft = { displayName: 'Container' };
createRoot(document.getElementById('app')).render(
<Editor resolver={{ Heading, Container }}>
<Frame>
<Element is={Container} canvas>
<Heading text="Hello editor" />
</Element>
</Frame>
</Editor>,
);
Craft.js 0.2.12 from the code above. There is no editor chrome because Craft.js does not ship any — this screenshot is the argument.
It reached a rendered editor in a median of 94 ms, second fastest in our benchmark, for the obvious reason: it renders almost nothing. Comparing that number with GrapesJS's 309 ms without noting what each library put on screen would be meaningless, which is why the benchmark page shows the screenshots next to the timings.
Strengths
Your editor looks like your product. No panels to restyle, no CSS specificity war with a vendor's stylesheet, no compromise between the editor's design language and yours.
The lightest option by a wide margin. 29.2 kB gzip against Puck's 90.4 kB and GrapesJS's 294.6 kB. If you were going to build custom UI anyway, you are not paying for UI you throw away.
A very small API. Two hooks and a rules object. You can read the surface in an afternoon, and there is little hidden behaviour to discover at 2am.
Drag-and-drop is genuinely hard, and this part is done. Nested drop targets, indicators, hit testing and the tree operations underneath them are the part most teams underestimate when they consider writing an editor from scratch. This is exactly the part Craft.js gives you.
Nothing is hosted. MIT licensed, no service, no account, no vendor.
Limitations
You are building an editor. Toolbars, settings panels, a layers view, block palettes and undo/redo UI are all yours. Our build-versus-buy calculator defaults to 120 hours for editor UI alone, and with Craft.js none of that is optional.
A quiet upstream. Releases are infrequent. For a library this small and stable that is survivable, but assume you may end up maintaining a fork, and price that in.
Almost no ecosystem. No plugin marketplace, few third-party integrations, and the examples you find online are usually one-off demos rather than maintained packages.
No styling system. Like Puck, users change props, not CSS — except here you also build the controls that change them.
Documentation stops where products start. The tutorial is good and takes you to a working editor. Questions about SSR, very large trees, and migrating stored state between component versions are answered in GitHub issues rather than documentation.
Pricing
Free, MIT licensed, no service and no ceiling. The cost is entirely engineering time, and it is the highest in this dataset for a customer-facing editor. That is a rational trade when the editing experience differentiates your product, and a poor one when it does not — which is the question the build-versus-buy page exists to make explicit before you commit a quarter to it.
Who Craft.js fits, and who it does not
Good fit
- Products where the editor UI must look like the rest of your application rather than like a generic builder
- React teams who want full control over the node tree, serialisation format and undo behaviour
- Building a narrow, opinionated editor — a form builder, a dashboard composer — rather than a general page builder
Poor fit
- Teams on a deadline who need panels, a layers tree and a toolbar without building them
- Non-React stacks, since the node model is built on React context and hooks
- Projects that expect a maintained plugin catalogue to fill capability gaps
Our scores for Craft.js
Scored 0–10 by the EditorStack team against the rubric on the methodology page. Each score is argued below it; a score with no argument fails the build.
- Developer experience7.5/10
The hook API — useNode and useEditor — is elegant and small, and connectors make an arbitrary component draggable in a couple of lines. The friction is that nothing is provided visually, so every early hour goes into building UI that other libraries hand you on install.
- Extensibility9/10
Because Craft.js only owns the tree and the interaction layer, there is almost nothing to fight: rules control what can be dropped where, custom node types carry their own settings panels, and the serialised state format is yours to shape. It is closer to a toolkit than a product, which is exactly the point.
- Documentation7/10
The guided tutorial is genuinely good and takes you from empty page to working editor. Beyond it, reference coverage thins out, and questions about SSR, large trees and state migration are usually answered in GitHub issues rather than in the docs.
- Ecosystem4.5/10
Development has been quiet compared with newer React builders, there is no plugin marketplace, and most integrations you find are one-off examples. Teams adopting it should assume they are on their own for anything beyond core drag-and-drop.
- Time to production5/10
Expect weeks, not days. You are building the editor, not configuring one — toolbars, layer panels, property editors and persistence are all your code. That is a deliberate trade for control, but it is the slowest route in this dataset to a customer-facing editor.
Craft.js against its nearest neighbours
The closest products in the dataset by category, with the facts most people open three tabs to compare. Bundle sizes marked in kilobytes are our own measurements.
Alternatives to Craft.js
Each comparison below is a full write-up, not a feature grid: where each tool wins, and what moving between them costs.
Frequently asked questions
- What is Craft.js used for?
- Building your own page editor inside a React application, when the editor's interface has to look like the rest of your product rather than like a generic builder. It is a toolkit, not a finished editor.
- How big is Craft.js?
- We measured @craftjs/core 0.2.12 at 29.2 kB gzip (89.3 kB raw) with React external — the lightest library in our benchmark, because it contains no editor UI.
- Does Craft.js work with React 19?
- Yes. Its peer range covers React 16.8 through 19, and our benchmark ran it successfully on React 19.2.8 with a rendered editor in a median of 94 ms.
- Craft.js or Puck?
- Puck if you want an editor now and can accept its interface; Craft.js if the interface is the point and you are prepared to build it. Puck is roughly three times the bundle size and a fraction of the work.
- Is Craft.js actively maintained?
- Development has been quiet compared with newer React builders — 0.2.12 is the current version. Evaluate it as a stable, small library you may end up maintaining a fork of, rather than as a fast-moving project.
Sources and verification
Last verified: . Facts on this page were checked against the sources below on the date shown next to each one.
- npm registry metadata for @craftjs/core (licence, first publish date, latest version) — accessed 2026-08-19
- Craft.js source repository — accessed 2026-08-19
- Craft.js documentation — accessed 2026-08-19