# Extension points — excalidraw/excalidraw

> Canonical page: https://codevetter.com/unpack/excalidraw/extension-points

# Extension points — excalidraw/excalidraw

Scanned commit 31df3e6ef245c646b18a055ccf858cd6117c7768 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

New editor commands are actions registered through register() and ActionManager, or at runtime via the imperative registerAction. Hosts extend rendering and behavior through Excalidraw props (UI slots, embeddables, tools, initial data) rather than forks. Persistence of libraries is an adapter interface. AI diagram-to-code is a setPlugins hook. Locale files and the library URL allowlist are data extension points.
- register(action) in packages/excalidraw/actions/register.ts appends to a module-level actions array and returns the action. Action files such as actionDeleteSelected.tsx call it at export time. App.tsx imports those modules for their side effects, then actionManager.registerAll(actions) plus undo/redo. The public API also exposes api.registerAction so hosts can add actions after mount. — [packages/excalidraw/actions/register.ts#L1-15](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/actions/register.ts#L1-L15) [packages/excalidraw/actions/actionDeleteSelected.tsx#L34-35](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/actions/actionDeleteSelected.tsx#L34-L35) [packages/excalidraw/components/App.tsx#L841-843](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/components/App.tsx#L841-L843) [packages/excalidraw/components/App.tsx#L941-943](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/components/App.tsx#L941-L943)
- Action objects carry name (ActionName union), perform, keyTest, keyPriority, PanelComponent, trackEvent, and an optional navigation flag. Adding a command requires extending the ActionName union in actions/types.ts or TypeScript will reject the register call. Key collisions are not merged: handleKeyDown warns and cancels when more than one keyTest matches. — [packages/excalidraw/actions/types.ts#L17-44](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/actions/types.ts#L17-L44) [packages/excalidraw/actions/types.ts#L45-144](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/actions/types.ts#L45-L144) [packages/excalidraw/actions/manager.tsx#L92-119](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/actions/manager.tsx#L92-L119)
- Host integration props on Excalidraw include onChange, onIncrement, onPointerDown/Up, onPaste, onDuplicate, onLibraryChange, onLinkOpen, onScrollChange, onUserFollow, renderTopLeftUI, renderTopRightUI, renderCustomStats, renderEmbeddable, validateEmbeddable, renderScrollbars, initialData, UIOptions, activeTool, interaction, and aiEnabled. aiEnabled defaults to on unless passed false. — [packages/excalidraw/index.tsx#L67-120](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/index.tsx#L67-L120) [packages/excalidraw/index.tsx#L207-260](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/index.tsx#L207-L260)
- interaction and ui config objects are compared semantically inside areEqual so hosts can inline them. Supported interaction.enabled keys include links, embeds, interactiveContent, navigation, browserZoom, and tools.laser / tools.custom. When interaction is false or a partial object, isInteractionEnabled returns false and the editor forces viewModeEnabled. — [packages/excalidraw/index.tsx#L306-347](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/index.tsx#L306-L347) [packages/excalidraw/components/App.tsx#L960-964](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/components/App.tsx#L960-L964) [packages/excalidraw/components/App.tsx#L896-902](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/components/App.tsx#L896-L902)
- Custom tools use activeTool.type === 'custom' (plus customType in the memo comparator). The pointer-down branch only applies the cursor; the host is expected to subscribe through onPointerDown. props.activeTool cannot force the image tool — the constructor console.warns and ignores it. — [packages/excalidraw/index.tsx#L294-300](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/index.tsx#L294-L300) [packages/excalidraw/components/App.tsx#L880-889](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/components/App.tsx#L880-L889) [packages/excalidraw/components/App.tsx#L8944-8946](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/components/App.tsx#L8944-L8946)
- LibraryPersistenceAdapter requires load({source}) and save(libraryData). The editor also has LibraryMigrationAdapter for one-shot legacy reads. useHandleLibrary and parseLibraryTokensFromUrl are public exports for hosts that supply library tokens on the URL. — [packages/excalidraw/data/library.ts#L76-100](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/data/library.ts#L76-L100) [packages/excalidraw/index.tsx#L460-462](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/index.tsx#L460-L462)
- DiagramToCodePlugin is the AI extension slot: it calls app.setPlugins({ diagramToCode: { generate } }) in a layout effect. The package does not implement the network call; excalidraw-app/components/AI.tsx supplies generate. TTD chat storage is a separate adapter (TTDIndexedDBAdapter) rather than this plugin map. — [packages/excalidraw/components/DiagramToCodePlugin/DiagramToCodePlugin.tsx#L7-18](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/components/DiagramToCodePlugin/DiagramToCodePlugin.tsx#L7-L18) [excalidraw-app/components/AI.tsx#L19-28](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/components/AI.tsx#L19-L28)
- Imperative ExcalidrawImperativeAPI methods created in createExcalidrawAPI include updateScene, applyDeltas, mutateElement, updateLibrary, addFiles, resetScene, setViewport, setElementRenderOverrides, setActiveTool, toggleSidebar, updateFrameRendering, onChange, onIncrement, onPointerDown, onPointerUp, onScrollChange, onUserFollow, onStateChange, and onEvent. history on the API currently only exposes clear. — [packages/excalidraw/components/App.tsx#L819-862](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/components/App.tsx#L819-L862)
- CaptureUpdateAction is the extension contract for programmatic scene writes. IMMEDIATELY pushes undo, NEVER is required for remote or init updates, EVENTUALLY batches multi-step async edits. It is re-exported from the package entry so hosts can pass it to updateScene. — [packages/element/src/store.ts#L38-69](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/element/src/store.ts#L38-L69) [packages/excalidraw/index.tsx#L460](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/index.tsx#L460)
- Feature flags are a localStorage map under excalidraw-feature-flags, read by getFeatureFlag and written by setFeatureFlag. The only flag today is COMPLEX_BINDINGS, default false. Pointer-up consults it to decide whether to reset delayed bind mode. Sentry also calls getFeatureFlag and enables featureFlagsIntegration. — [packages/common/src/utils.ts#L1184-1226](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/common/src/utils.ts#L1184-L1226) [packages/excalidraw/components/App.tsx#L9031-9033](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/components/App.tsx#L9031-L9033) [excalidraw-app/sentry.ts#L1](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/sentry.ts#L1)
- New locales are a data plug-in: add packages/excalidraw/locales/<code>.json (Crowdin writes these from en.json) and an entry in the languages array in i18n.ts, including rtl when needed. Vite already chunks every locale file except en.json and percentages.json. — [packages/excalidraw/i18n.ts#L19-40](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/i18n.ts#L19-L40) [crowdin.yml#L1-2](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/crowdin.yml#L1-L2) [excalidraw-app/vite.config.mts#L106-118](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/excalidraw-app/vite.config.mts#L106-L118)
- WorkerPool.create(workerUrl) is the hook for short-lived module workers (font subsetting). Callers must pass a URL that is not the main bundle. Idle workers are terminated after ttl milliseconds, default 1000, and the pool does not cap concurrency — the comment says the caller must. — [packages/excalidraw/workers.ts#L19-59](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/workers.ts#L19-L59)
- UI composition components are exported for hosts: Sidebar, Button, Footer, MainMenu, WelcomeScreen, LiveCollaborationTrigger, Stats, plus useExcalidrawAPI and ExcalidrawAPIProvider so the API can be read outside the editor tree. Tunnels for slot rendering live in packages/excalidraw/context/tunnels.ts. — [packages/excalidraw/index.tsx#L52-65](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/index.tsx#L52-L65) [packages/excalidraw/index.tsx#L464-477](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/index.tsx#L464-L477) [packages/excalidraw/context/tunnels.ts](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/packages/excalidraw/context/tunnels.ts)
- Examples are the supported embed templates: examples/with-nextjs (App Router page plus a Pages Router route, client-only dynamic import) and examples/with-script-in-browser (Vite, ExampleApp, CustomFooter). yarn start:example builds packages then starts the script example. dev-docs is a separate Docusaurus site and is not a yarn workspace of the root package.json. — [examples/with-nextjs/src/app/page.tsx#L6-25](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/examples/with-nextjs/src/app/page.tsx#L6-L25) [package.json#L4-8](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/package.json#L4-L8) [package.json#L67](https://github.com/excalidraw/excalidraw/blob/31df3e6ef245c646b18a055ccf858cd6117c7768/package.json#L67)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
