The editor is split into eight packages in a layered dependency direction.
| Package | Role |
|---|---|
@editorjs/sdk |
Shared contracts — interfaces, base event classes, EventBus |
@editorjs/model |
In-memory document model (EditorJSModel) |
@editorjs/dom-adapters |
Binds model nodes to DOM inputs; default adapter implementation |
@editorjs/collaboration-manager |
Operational transformation, batching, undo/redo, OT WebSocket client |
@editorjs/core |
Orchestrator — IoC container, plugin/tool lifecycle, EditorAPI |
@editorjs/ui |
Default UI shell — EditorjsUI, BlocksUI, Toolbar, InlineToolbar, Toolbox |
@editorjs/ot-server |
Standalone WebSocket OT server — OTServer, DocumentManager |
playground |
Vite dev sandbox; not published |
sdkis the contract layer all other packages depend on.corewires runtime dependencies; it should be the only orchestrator.modeldoes not depend on DOM concerns.dom-adaptersandcollaboration-managerobserve/apply model changes through public APIs and events.uidepends onsdkonly; it is registered as anEditorjsPluginviacore.use().ot-serverdepends oncollaboration-manager(forOperation/ message types) andmodel; it runs server-side only.
Core is the entry point and owner of service wiring. Most services are wired in the constructor; core.use(...) registers UI plugins and tools; initialize() prepares tools, initializes the model, and starts collaboration.
BlocksUI owns the contenteditable blocks holder. It intercepts browser beforeinput events, normalises them into BeforeInputUIEvent, and dispatches them on the global EventBus. It also listens for BlockAddedCoreEvent / BlockRemovedCoreEvent to insert/remove rendered block elements in the DOM.
OTServer is a standalone Node.js WebSocket server. It maintains one DocumentManager per documentId. On each incoming Operation message it transforms the operation against any conflicting operations (ops with a higher or equal revision number), bumps the revision, applies the result to its own EditorJSModel copy, and broadcasts the transformed operation to all connected clients for that document.
Direct cross-layer coupling should be avoided: use interfaces/events from sdk and mutation APIs from EditorJSModel.
→ diagrams/architecture-overview.mmd
Package boundaries and integration contracts. Keep this as the high-level map; see other docs for per-subsystem flow details.