# Craft.js review: build your own React page editor

*Source: https://www.editorstack.cc/libraries/craftjs — last updated 2026-08-19. Licensed CC BY 4.0 with attribution to EditorStack.*


## Summary

- 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.

## Quick facts

| Fact | Value |
| --- | --- |
| Type | library |
| Licence | MIT |
| First release | 2019-12 |
| Language | TypeScript |
| Frameworks | React |
| SSR support | partial |
| Bundle (min+gzip) | 29.2 kB gzip |
| Pricing | Free (open source) |
| npm weekly downloads | 64,907 |
| GitHub stars | pending sync |
| Latest version | 0.2.12 |
| Last verified | 2026-08-19 |
| Drag & drop canvas | Yes |
| Responsive breakpoints | No |
| Visual style manager | No |
| Custom components | Yes |
| Data binding | Partial |
| E-commerce blocks | No |
| Email HTML export | No |
| AI generation | No |
| Editor i18n | No |
| White label | Yes |
| Self-hosted | Yes |

## 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](/libraries/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.

```jsx
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>,
);
```

![The Craft.js benchmark application rendering a draggable heading with no editor chrome around it](https://www.editorstack.cc/screenshots/craftjs-minimal.png)

*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](/research/time-to-first-editor-benchmark) 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](/use-cases/build-vs-buy-visual-editor)
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](/use-cases/build-vs-buy-visual-editor) exists to make explicit before you
commit a quarter to it.

## Who it 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


## Craft.js against its nearest neighbours

| Product | Type | Licence | Frameworks | Bundle (min+gzip) | Price from | Self-hosted | White label | Score |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| [Craft.js](https://www.editorstack.cc/libraries/craftjs) | library | MIT | React | 29.2 kB gzip | Free (open source) | Yes | Yes | 6.6 |
| [BlockNote](https://www.editorstack.cc/libraries/blocknote) | library | MPL-2.0 | React, Vue | 386.1 kB gzip | from $195/mo | Yes | Yes | not scored |
| [Lexical](https://www.editorstack.cc/libraries/lexical) | library | MIT | Any (framework-agnostic) | 104.9 kB gzip | Free (open source) | Yes | Yes | 7.4 |
| [Plate](https://www.editorstack.cc/libraries/plate) | library | MIT | React | 150.8 kB gzip | Free (open source) | Yes | Yes | 8 |


## Our scores

- **developer experience: 7.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.
- **extensibility: 9/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.
- **documentation: 7/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.
- **ecosystem: 4.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 production: 5/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.


## Alternatives

- [Craft.js vs Builder.io](https://www.editorstack.cc/compare/craftjs-vs-builder-io)
- [Craft.js vs Plasmic](https://www.editorstack.cc/compare/craftjs-vs-plasmic)
- [Craft.js vs React Page](https://www.editorstack.cc/compare/craftjs-vs-react-page)
- [Craft.js vs GrapesJS](https://www.editorstack.cc/compare/grapesjs-vs-craftjs)
- [Craft.js vs Puck](https://www.editorstack.cc/compare/puck-vs-craftjs)


## 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

1. [npm registry metadata for @craftjs/core (licence, first publish date, latest version)](https://registry.npmjs.org/@craftjs/core) — accessed 2026-08-19
2. [Craft.js source repository](https://github.com/prevwong/craft.js) — accessed 2026-08-19
3. [Craft.js documentation](https://craft.js.org/docs/overview) — accessed 2026-08-19
