Fabric.js Document Engine

Search documentation

Find a page or section

中文

Plain JavaScript

View as Markdown

No framework, no build step required, just the engine and the DOM.

The engine has no framework code in its core, so Fabric.js plain JavaScript works as well as any framework. You create the canvas, create the engine, and update the toolbar from its state.

The page

<div role="toolbar">
  <button id="undo">Undo</button>
  <button id="redo">Redo</button>
  <button id="save">Save</button>
  <span id="status" aria-live="polite"></span>
</div>
<canvas id="editor"></canvas>

The script

import { Canvas } from "fabric";
import {
  bindKeyboardShortcuts,
  createDocumentEngine,
  createDocumentStateStore,
} from "fabricjs-document-engine";
import { createLocalStorage } from "fabricjs-document-engine/storage";
 
const canvas = new Canvas("editor", { width: 800, height: 500 });
const engine = createDocumentEngine({
  canvas,
  storage: createLocalStorage(),
  autosave: true,
});
bindKeyboardShortcuts(engine);
 
const undo = document.querySelector<HTMLButtonElement>("#undo")!;
const redo = document.querySelector<HTMLButtonElement>("#redo")!;
const save = document.querySelector<HTMLButtonElement>("#save")!;
const status = document.querySelector("#status")!;
 
undo.addEventListener("click", () => engine.undo());
redo.addEventListener("click", () => engine.redo());
save.addEventListener("click", () => engine.save());
 
const store = createDocumentStateStore(engine);
 
function render() {
  const state = store.getSnapshot();
  undo.disabled = !state.canUndo;
  redo.disabled = !state.canRedo;
  save.disabled = !state.isDirty;
  status.textContent = state.saveStatus;
}
 
store.subscribe(render);
render();

createDocumentStateStore gives you one snapshot with everything a toolbar needs. It only listens to the engine while it has subscribers.

Events instead of a store

If you only need one value, listen to a single event instead:

engine.on("history:change", ({ canUndo, canRedo }) => {
  undo.disabled = !canUndo;
  redo.disabled = !canRedo;
});

on returns an unsubscribe function. The full list is in events.

Without a bundler

Fabric.js plain JavaScript also works straight from a CDN with an import map. The package is published as ES modules:

<script type="importmap">
  {
    "imports": {
      "fabric": "https://cdn.jsdelivr.net/npm/fabric@7/+esm",
      "fabricjs-document-engine": "https://cdn.jsdelivr.net/npm/fabricjs-document-engine@1/+esm"
    }
  }
</script>

For a step-by-step build without a framework, follow the editor tutorial.