Skip to main content

Installing Plugins

engine.use() — one plugin at a time

import { createEngine } from "@rifrocket/fabricjs-design-tool";
import { shapesBasicPlugin } from "@rifrocket/fdt-plugin-shapes-basic";

const engine = createEngine(canvasElement);
engine.use(shapesBasicPlugin);

use() calls plugin.install(engine) immediately and throws if a plugin with the same name is already installed. It does not consult dependsOn — installation order is exactly the order you call use().

engine.useAll() — many at once, dependency-ordered

engine.useAll([shapesBasicPlugin, qrCodePlugin, myPropertyFieldsPlugin]);

useAll() topologically sorts the given plugins by their dependsOn arrays before installing, so you don't have to get array order right by hand:

const myPropertyFieldsPlugin: EditorPlugin = {
name: "my-property-fields",
dependsOn: ["shapes-basic", "qrcode"], // installed first, regardless of array position
install(engine) {
engine.registry.registerPropertyFields("rect", [...]);
},
};

engine.useAll([myPropertyFieldsPlugin, shapesBasicPlugin, qrCodePlugin]); // order doesn't matter

If a listed plugin depends on a name that's neither already installed nor present in the same useAll() call, it throws — a missing dependency fails loudly rather than silently installing in the wrong order. A circular dependsOn chain also throws.

<Editor plugins={[...]}> and <DesignEditor preset="..." plugins={{ add: [...] }}> both call useAll() internally, so the same ordering guarantee applies whether you're calling core directly or going through the React adapter.

The construction-time-only contract

plugins (on <Editor>) and preset/plugins (on <DesignEditor>) are read once, at construction. Changing them on an already-mounted component does nothing — there's no safe general story for hot-swapping an installed plugin set, because uninstalling one correctly would require knowing everything it registered and whether any other plugin has since come to depend on it. To install a different plugin set, remount with a different key:

// Switching key remounts the whole engine with the new plugin set:
<Editor key={workspaceId} plugins={pluginsForWorkspace(workspaceId)} />

This applies identically whether you're using <Editor>, <DesignEditor>, or useCanvasEngine() directly.

Removing a plugin: unuse()

engine.unuse("local-storage"); // calls uninstall?.(engine) if the plugin defines one, then forgets it

Worth knowing before you rely on it: of the plugins that ship today, 8 implement a real uninstall()local-storage, alignment, snapping, devtools, clipboard, effects, effects-panel, and shapes-basic-panel (all either unregister their panel(s) or their keyboard shortcuts). Calling unuse() on the other 9 removes it from the installed-plugins list but leaves whatever it registered (object types, importers) in place — there's no automatic "undo everything this plugin did," since what "uninstalling an object type with live objects of that type still on canvas" should even mean isn't a settled question. Treat unuse() as reliable for plugins you know implement uninstall(), and prefer the remount-with-a-new-key pattern above for a full plugin-set change.

Overriding a preset's plugin list

<DesignEditor preset="default"> and createEditor({ preset }) both accept a plugins override object, applied per-field rather than all-or-nothing:

<DesignEditor
preset="default"
plugins={{
exclude: ["qrcode", "export-pdf"],
add: [myBrandKitPlugin],
replace: { effects: createEffectsPlugin([shadowEffect, glowEffect]) },
}}
/>

exclude and replace throw if given a plugin name that isn't actually in the resolved preset — a typo in an exclude list fails loudly instead of silently doing nothing. See Presets for the full override model.

Errors during install

If a plugin's install() throws while inside useAll(), the error is wrapped to name the responsible plugin (Plugin "X" failed to install: <original message>), with the original error attached as .cause — useful because useAll() installs several plugins in one call, so without this you'd otherwise have to bisect your plugin list by hand to find which one caused a registry conflict (e.g. two plugins registering the same object-type id).