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.