Fabric.js save and load, undo and redo, done right
Works with the stack you already use
Fabric.js Document Engine
Everything your canvas editor needs around the canvas
Fabric.js draws and edits objects. This engine adds the rest of a real canvas editor: Fabric.js save and load, undo redo, autosave, export and recovery. Your canvas, toolbar and UI stay yours.
Explore the features
- Learn more
Undo and redo
Built inFabric.js has no undo built in. Get one undo step per user action, with step labels and keyboard shortcuts.
- Learn more
Save and load
Built inFabric.js save and load with stable object ids. Custom properties and images come back exactly as they were.
- Learn more
Autosave
Needs storageSaves while people edit, one save at a time, with retries. An old save never overwrites newer work.
- Learn more
Save conflicts
Needs storageRevision checks notice when another tab or device saved first, and let the user choose what to keep.
- Learn more
Images, fonts and export
Built inExport PNG, JPEG, WebP, SVG or JSON. Missing images, fonts and tainted canvases are found before an export fails.
- Learn more
Versions
Needs storageKeep named versions of a document and restore any of them without losing the current work.
- Learn more
Recovery
OptionalUnsaved work is copied to IndexedDB while people edit, and offered back after a crash or refresh.
- Learn more
React hooks
OptionalOptional hooks create the engine with your canvas and feed your toolbar. Vue, Svelte and plain JavaScript work too.
Live examples
See every feature running
Each example is a real Fabric.js canvas running the package from npm. Try it here, then copy its code from the guide into your own editor.
Browse the guides- Live
Save conflicts
Two tabs save one document. The second one gets a conflict to resolve.
Read the guide
Developer docs
Clear guides, live examples and a full API reference, from your first Fabric.js save and load to a production editor.
Documentationimport { useDocumentEngine, useDocumentState } from "fabricjs-document-engine/react";
import { createLocalStorage } from "fabricjs-document-engine/storage";
const storage = createLocalStorage();
export function Editor() {
const { elementRef, canvas } = useFabricCanvas(800, 500);
const engine = useDocumentEngine(canvas, { storage, autosave: true });
const state = useDocumentState(engine);
return (
<>
<button disabled={!state?.canUndo} onClick={() => engine?.undo()}>
Undo {state?.undoLabel}
</button>
<canvas ref={elementRef} />
</>
);
}<script setup lang="ts">
import { Canvas } from "fabric";
import { createDocumentEngine } from "fabricjs-document-engine";
import { onMounted, shallowRef, useTemplateRef } from "vue";
const element = useTemplateRef<HTMLCanvasElement>("element");
const engine = shallowRef();
onMounted(() => {
const canvas = new Canvas(element.value!, { width: 800, height: 500 });
engine.value = createDocumentEngine({ canvas });
});
</script>
<template>
<button @click="engine?.undo()">Undo</button>
<canvas ref="element" />
</template>import { Canvas } from "fabric";
import { createDocumentEngine } 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,
});
await engine.load("drawing-1");
await engine.undo();