Doramagic Project Pack · Human Manual
ckeditor5
Powerful rich text editor framework with a modular architecture, modern integrations, and features like collaborative editing.
CKEditor 5 Overview and Core Architecture
Related topics: Core Editing Features and Data Flow, Framework, Plugins, and Extensibility, Installation, Configuration, and Framework Integration
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Core Editing Features and Data Flow, Framework, Plugins, and Extensibility, Installation, Configuration, and Framework Integration
CKEditor 5 Overview and Core Architecture
Purpose and Scope
CKEditor 5 is a modern JavaScript rich-text editor with MVC architecture, a custom data model, and a virtual DOM, written from scratch in TypeScript. It targets every type of WYSIWYG editing solution, from Google Docs–style collaborative documents to Slack- or Twitter-like applications, all built on a single editing framework. Source: README.md:6-10
The repository at the GitHub URL is the development monorepo that centralizes work across all CKEditor 5 packages and provides the helper tooling (builder, test runner, release scripts) used to produce the published artifacts. Source: README.md:30-35
The currently shipped version line is v48.2.0, with media embed improvements (notably resizable media via drag handles) as one of the most recent additions. Source: packages/ckeditor5/package.json:3, README.md:62-67
Monorepo Structure and Build Toolchain
CKEditor 5 is a modular, multi-package monorepo. Each feature is published as an individual npm package under the @ckeditor/ scope and is consumed either independently (framework integration) or through the bundled ckeditor5 meta-package that re-exports the ready-to-use editor builds. Source: README.md:32-37, packages/ckeditor5/package.json:8-25
The root package.json declares the workspace tooling. It pins the supported engines and package manager:
| Requirement | Value | Source |
|---|---|---|
| Node.js | >=24.11.0 | package.json:13 |
| pnpm | >=10.28.0 | package.json:14 |
| Yarn | notice only ("we use pnpm now") | package.json:15-19 |
All packages are authored as native ES modules ("type": "module") and are shipped with full TypeScript declarations under ./dist/index.d.ts. The exports map exposes both the source root (./src/index.ts) for the development workspace and the compiled ./dist/* artifacts for consumers. Source: packages/ckeditor5/package.json:26-44, packages/ckeditor5-core/package.json:24-42
Cross-package dependencies use the workspace:* protocol, indicating a pnpm workspace layout where every package in packages/* is a workspace member. Source: packages/ckeditor5-bookmark/package.json:36-43, packages/ckeditor5-essentials/package.json:36-44
Layered Architecture: Core, Engine, Features
The architecture follows a strict layering. Every feature package depends on ckeditor5-core and/or ckeditor5-engine, never the reverse, which preserves a clean dependency direction.
flowchart TB
subgraph App["Application / Bundler"]
Editor["ckeditor5 (meta-package)"]
end
subgraph Features["Feature Packages"]
Para["ckeditor5-paragraph"]
Head["ckeditor5-heading"]
Book["ckeditor5-bookmark"]
Mnt["ckeditor5-mention"]
Src["ckeditor5-source-editing"]
PB["ckeditor5-page-break"]
MD["ckeditor5-markdown-gfm"]
Ess["ckeditor5-essentials (bundle)"]
end
subgraph Engine["Editing Engine Layer"]
Eng["ckeditor5-engine"]
UI["ckeditor5-ui"]
Ut["ckeditor5-utils"]
end
subgraph Core["Core Layer"]
C["ckeditor5-core"]
end
Editor --> Ess
Ess --> Para
Ess --> Head
Para --> C
Para --> Eng
Para --> UI
Para --> Ut
Head --> C
Head --> Eng
Book --> C
Book --> Eng
Book --> UI
Mnt --> C
Mnt --> Eng
Mnt --> UI
Src --> C
Src --> UI
Src --> Ut
MD --> C
MD --> Eng
C --> Eng
UI --> Ut@ckeditor/ckeditor5-core— The core architecture (editor lifecycle, plugin collection, command system,Editorclass). Source: packages/ckeditor5-core/package.json:4-5, packages/ckeditor5-core/README.md:1-20@ckeditor/ckeditor5-engine— The editing engine (custom data model, schema, converters, view layer, undo/redo via OT). Source: packages/ckeditor5-engine/README.md:1-30, packages/ckeditor5-engine/README.md:42-46- Feature packages — Each implements a single user-visible capability (paragraphs, headings, bookmarks, mentions, source editing, page break, GFM Markdown, language parts). Source: packages/ckeditor5-paragraph/package.json:4-5, packages/ckeditor5-heading/README.md:30-36, packages/ckeditor5-bookmark/package.json:4-5, packages/ckeditor5-source-editing/package.json:4-5, packages/ckeditor5-mention/package.json:4-5, packages/ckeditor5-page-break/package.json:4-5, packages/ckeditor5-markdown-gfm/package.json:4-5, packages/ckeditor5-language/README.md:30-36
@ckeditor/ckeditor5-essentials— A curated bundle of the most common features (clipboard, enter, select-all, typing, undo) that most editors include by default. Source: packages/ckeditor5-essentials/package.json:4-5, packages/ckeditor5-essentials/package.json:36-44@ckeditor/ckeditor5-utils— Low-level helpers such as theglobalmodule that exposeswindowanddocumentin a test-stubbable way. Source: packages/ckeditor5-utils/src/dom/global.ts:18-26
Developer Workflow and Community Context
The framework is written from scratch in TypeScript, ships its own .d.ts typings (a long-standing community request, see #504 "Typings for TypeScript"), and works with modern bundlers. Type support is published via the publishConfig.types field pointing to ./dist/index.d.ts. Source: packages/ckeditor5/package.json:32-36, README.md:10-15
A few operational notes from the source tree that new contributors should be aware of:
- License: dual-licensed under GPL-2.0-or-later or a commercial CKSource license. The
LICENSE.mdfile is referenced from everypackage.json. Source: packages/ckeditor5-core/package.json:8-9, README.md:78-87 - Side effects: declared per package and limited to
*.cssand translation UMD bundles, which keeps tree-shaking effective for end users. Source: packages/ckeditor5-markdown-gfm/package.json:35-38 - Issue reporting: bugs and feature requests are tracked in the main
ckeditor/ckeditor5repository, not per-package. Source: README.md:68-72 - Next.js / SSR: the community has documented that new installation methods shipped in v42.0.0 work seamlessly with Next.js (issue #7376), reflecting the move to ESM-first packages.
- Drag-and-drop content: still a tracked feature gap (issue #2664) — the engine supports copy/paste of HTML and plain text and file drop, but in-editor drag of existing content is not fully supported.
- Media embed resizing: delivered in the current v48.2.0 release using the same widget resizer pattern as image resize, fulfilling the request in issue #6593.
See Also
- README.md — Project overview and quick-start links.
- packages/ckeditor5-core/README.md — Core editor architecture entry point.
- packages/ckeditor5-engine/README.md — Editing engine architecture (data model, view, OT).
- packages/ckeditor5/package.json — Bundled distribution meta-package.
- package.json — Workspace root and engine requirements.
Source: https://github.com/ckeditor/ckeditor5 / Human Manual
Core Editing Features and Data Flow
Related topics: CKEditor 5 Overview and Core Architecture, Framework, Plugins, and Extensibility
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: CKEditor 5 Overview and Core Architecture, Framework, Plugins, and Extensibility
Core Editing Features and Data Flow
CKEditor 5 is a modern JavaScript rich-text editor with MVC architecture, a custom data model, and a virtual DOM, written from scratch in TypeScript. Source: README.md. It is organized as a modular monorepo (packages/*) in which a core editing engine and dozens of feature plugins combine into composable editors. This page documents the core editing pipeline, the data-controller contract, and the plugins that participate in it.
Repository and Package Layout
The repository is a pnpm-based monorepo. The root package.json requires Node >=24.11.0 and pnpm >=10.28.0, and aggregates @ckeditor/ckeditor5-dev-* tooling plus per-package dev dependencies. Engine and tooling are kept independent of any single feature.
The umbrella build artifact is the ckeditor5 package (version 48.2.0). Its published entry point is ./dist/ckeditor5.js with TypeScript declarations in ./dist/index.d.ts, and it re-exports the entire feature surface (e.g. ./*). Each feature lives in its own workspace package and re-exports its own src/index.ts for development, e.g.:
| Package | Purpose | Source |
|---|---|---|
@ckeditor/ckeditor5-engine | MVC editing engine, data controller, data processors | packages/ckeditor5-engine/README.md |
@ckeditor/ckeditor5-core | Editor class, plugin lifecycle, command bus | packages/ckeditor5-core/README.md |
@ckeditor/ckeditor5-utils | Shared helpers (DOM, mixins, env) | packages/ckeditor5-utils/src/mix.ts |
@ckeditor/ckeditor5-image | Inline/block images, resize, caption, alternative text | packages/ckeditor5-image/src/image.ts |
@ckeditor/ckeditor5-markdown-gfm | GitHub Flavored Markdown output/paste | packages/ckeditor5-markdown-gfm/README.md |
@ckeditor/ckeditor5-source-editing | Raw HTML view via SourceEditing plugin | packages/ckeditor5-source-editing/README.md |
@ckeditor/ckeditor5-language | Text part language | packages/ckeditor5-language/README.md |
@ckeditor/ckeditor5-bookmark | Named anchors/bookmarks | packages/ckeditor5-bookmark/README.md |
@ckeditor/ckeditor5-page-break | Block-level page break | packages/ckeditor5-page-break/README.md |
@ckeditor/ckeditor5-typing | Typing input pipeline | packages/ckeditor5-typing/README.md |
This split is deliberate: the engine package is "schema-less" and provides only primitives such as the data controller, conversion, and a virtual DOM. Feature packages register their own model elements (for example imageBlock) and converters on top of those primitives.
Data Pipeline and the Data Controller
CKEditor 5's editing engine maintains a tree-structured model that is separate from the DOM. The DataController (packages/ckeditor5-engine/src/controller/datacontroller.ts) is the single contract between the model and external serialization formats. It owns:
get()/set()for the editor's data (HTML, Markdown, or any registered processor).stringify()andtoModel()for one-shot conversion of an arbitrary string.registerHtmlPassthroughProcessor()for raw HTML pass-through used by source editing.insertContent(),getSelectedContent(), anddeleteContent()for clipboard-style data exchange with paste/drop handlers.
The engine also defines two data processors that plugins can plug in or override:
HtmlDataProcessor(packages/ckeditor5-engine/src/dataprocessor/htmldataprocessor.ts) — the default processor used bysetData('html', ...)andgetData(). It usesXmlDataProcessorinternally for tokenization and then post-processes the result into semantic HTML.XmlDataProcessor(packages/ckeditor5-engine/src/dataprocessor/xmldataprocessor.ts) — a generic, schema-aware XML/HTML tokenizer that powers both the HTML and Markdown processors.
flowchart LR
A[External HTML / Markdown] --> B[DataProcessor<br/>HtmlDataProcessor / GFMDataProcessor]
B --> C[DataController.toModel]
C --> D[Editing Model<br/>tree-structured]
D --> E[Conversion pipeline<br/>upcast + downcast]
E --> F[Editing view<br/>virtual DOM]
F --> G[Browser DOM<br/>contenteditable]
G --> F
D --> H[DataController.stringify]
H --> I[DataProcessor]
I --> J[External HTML / Markdown]A subtle but important property of the engine is that the model is the source of truth: user input flows from the DOM through the view into the model, and any change is then re-rendered back to the view. This two-way pipeline is what enables Operational Transformation for real-time collaboration, because operations are recorded against the model rather than the DOM. Source: packages/ckeditor5-engine/README.md.
Community issue #2664 ("Add support for content drag&drop") is essentially a request to enrich this pipeline so that the same data-controller entry points (insertContent, getSelectedContent) handle drag-and-drop of model fragments in addition to HTML, plain text, and files.
Feature Plugin Anatomy
Every editor feature is implemented as a Plugin whose static get requires() lists the plugins it depends on, and whose init() method mutates the schema, registers converters, and binds commands. Image handling is a canonical example:
- The umbrella image plugin in packages/ckeditor5-image/src/image.ts re-exports
Image,ImageBlock,ImageInline,ImageCaption,ImageStyle,ImageResize, andImageAlternativeTextas a single ergonomic surface. ImageBlockEditing(packages/ckeditor5-image/src/image/imageblockediting.ts) declares its dependency onImageEditing,ImageSizeAttributes,ImageUtils,ImagePlaceholder, andClipboardPipeline, registers theimageBlockmodel element asinheritAllFrom: '$blockObject'withallowAttributes: [ 'alt', 'src', 'srcset' ], and — only whenImageInlineEditingis also present — registers animageTypeBlockcommand that converts inline images into block images.- Resize support is split into
ImageResizeEditing(packages/ckeditor5-image/src/imageresize/imageresizeediting.ts) andImageResizeHandles(packages/ckeditor5-image/src/imageresize/imageresizehandles.ts), which mount drag handles on selected images and write back width/height attributes to the model.
This pattern — schema declaration, upcast/downcast converters, optional commands, and an opt-in requires graph — is repeated by every feature. Mixin composition is enabled by packages/ckeditor5-utils/src/mix.ts, which exports the Constructor and Mixed<Base, Mixin> helper types used throughout the engine and feature plugins.
The same shape is used for media-embed resizing, which landed in v48.2.0 alongside the table-style and output-format improvements highlighted in the release notes. Community issue #6593 ("Media embed resizing") — and the long-running #1627 ("Possible to make editor.getData() returns content with inline styles?") about HTML serialization — are both addressed by working within this conversion layer: a converter or processor change can change the serialized output without touching the model.
Environment and Cross-Cutting Helpers
Two non-feature packages underpin everything else:
- The
globalhelper (packages/ckeditor5-utils/src/dom/global.ts) exposeswindowanddocumentthrough a typedGlobalTypeobject. The fallbacktry/catchblock ensures that modules like the data controller can be loaded in non-DOM environments (e.g. SSR during Next.js builds), which is the prerequisite for the Next.js integration requested in community issue #7376 ("Next.js integration"). - The package metadata in packages/ckeditor5/package.json marks the build as
"type": "module"and ships both ESM (./src/index.tsduring dev,./dist/ckeditor5.jsin production) and generated TypeScript types. TypeScript support was the subject of long-running issue #504 ("Typings for TypeScript"); the engine and the umbrella package now publish.d.tsdeclarations.
Other features slot into the same architecture:
- Markdown I/O via
@ckeditor/ckeditor5-markdown-gfmregisters an additionalDataProcessoron the engine's data controller so thateditor.getData({ outputFormat: 'markdown' })andsetData(..., 'markdown')work transparently. - Raw source editing via
@ckeditor/ckeditor5-source-editingtoggles a passthrough processor (registered throughDataController.registerHtmlPassthroughProcessor()) so the view displays literal HTML while changes are still reconciled through the model. - Inline language tags, bookmarks, page breaks, and typing input (ckeditor5-language, ckeditor5-bookmark, ckeditor5-page-break, ckeditor5-typing) all follow the same recipe: declare a model element, register upcast/downcast, optionally expose a command.
Common Failure Modes and Usage Notes
- Initialization order matters. Because each plugin's
requiresis resolved by the editor class beforeinit(), a missing dependency surfaces as anCannot read properties of undefinedinsideinit(), not as aplugin-not-founderror. Always import the umbrella plugin (e.g.Image) rather than piecemeal sub-plugins when unsure. - Data is round-tripped through the model.
editor.getData()returns whateverHtmlDataProcessor(or the active processor) emits. Inserting model-only constructs without a downcast converter yields empty output, while inserting DOM-only markup without an upcast converter silently drops attributes — this is the root cause of issue #1627. - The data controller is the only sanctioned entry point. Clipboard, drag-and-drop, paste-from-Word, and Markdown paste all funnel through
DataController.insertContent()and friends. Custom paste pipelines should hook these methods instead of listening to DOMpasteevents directly, which is the architectural response to issue #2664. - SSR / Node.js usage is supported only via the
globalhelper. The editor will not crash on import ifwindowis missing because the helper catches and degrades gracefully (packages/ckeditor5-utils/src/dom/global.ts), but actually creating an editor requires a DOM, so server-rendered integrations such as Next.js need a dynamic-import boundary — the approach documented in connection with issue #7376.
See Also
- Editing engine architecture — packages/ckeditor5-engine/README.md
- Core editor and plugin lifecycle — packages/ckeditor5-core/README.md
- Project overview and quick start — README.md
- Image feature composition — packages/ckeditor5-image/src/image.ts
- Markdown output and paste — packages/ckeditor5-markdown-gfm/README.md
- Source editing plugin — packages/ckeditor5-source-editing/README.md
Source: https://github.com/ckeditor/ckeditor5 / Human Manual
Framework, Plugins, and Extensibility
Related topics: CKEditor 5 Overview and Core Architecture, Core Editing Features and Data Flow, Installation, Configuration, and Framework Integration
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: CKEditor 5 Overview and Core Architecture, Core Editing Features and Data Flow, Installation, Configuration, and Framework Integration
Framework, Plugins, and Extensibility
1. Purpose and Scope
CKEditor 5 is a modular, multi-package monorepo that delivers a modern, JavaScript rich-text editor written from scratch in TypeScript. It uses an MVC architecture with a custom tree-structured data model and an editing-oriented virtual DOM, designed to abstract away contentEditable browser quirks (README.md).
The framework is intentionally split between a small core, a feature-rich engine, and a large catalog of plugin packages. Feature packages such as ckeditor5-bookmark, ckeditor5-source-editing, ckeditor5-highlight, ckeditor5-page-break, ckeditor5-style, and ckeditor5-markdown-gfm are independent packages that depend on shared core and engine packages via workspace references (packages/ckeditor5-markdown-gfm/package.json, packages/ckeditor5-page-break/package.json).
The current release line is v48.2.0, distributed as ES modules with "type": "module" and published via pnpm workspaces (package.json, packages/ckeditor5/package.json).
2. Plugin Architecture
The core package is the heart of the extension model. Every editor capability is implemented as a Plugin registered with the editor. Plugins are aggregated through a PluginCollection, while user-facing actions are encapsulated as Command instances stored in a CommandCollection (packages/ckeditor5-core/src/plugin.ts, packages/ckeditor5-core/src/plugincollection.ts, packages/ckeditor5-core/src/command.ts, packages/ckeditor5-core/src/commandcollection.ts).
The framework encourages a decoupled, event-based design: features do not depend on each other directly, but communicate through standardized interfaces defined by the schema-less engine (packages/ckeditor5-engine/README.md). A Context provides the shared environment (locale, plugins, configuration) that one or more Editor instances can attach to, enabling headless use cases such as running CKEditor 5 inside Node.js for processing (packages/ckeditor5-core/src/context.ts, packages/ckeditor5-core/src/editor/editor.ts).
flowchart LR
Context --> Editor
Editor --> PluginCollection
PluginCollection --> PluginA["Feature Plugin\n(e.g. ckeditor5-bookmark)"]
PluginCollection --> PluginB["UI Plugin\n(e.g. toolbar)"]
PluginCollection --> PluginC["Data Processor\n(e.g. ckeditor5-markdown-gfm)"]
Editor --> CommandCollection
CommandCollection --> CommandA["Bold"]
CommandCollection --> CommandB["Insert Table"]
Engine["Editing Engine\n(virtual DOM + OT)"] --> EditorPlugins can declare dependencies on other plugins, register commands, hook into the engine's pipeline (conversion, schema, post-fixers), and contribute UI components through the dedicated UI package (packages/ckeditor5-ui/README.md).
3. Extensibility Patterns
Mixin-based Composition
Beyond standard class inheritance, the codebase promotes mixin composition. The utility module mix exposes helper types Constructor and Mixed that allow developers to combine base classes with mixin interfaces in a type-safe manner (packages/ckeditor5-utils/src/mix.ts). This is the preferred pattern for cross-cutting concerns such as event handling or observable behavior, which is heavily used by plugins.
Test-Friendly DOM Access
The global helper provides a single, stubbable access point for window and document, which makes it possible to write deterministic tests for browser-only code paths (packages/ckeditor5-utils/src/dom/global.ts). Combined with the @vitest/browser-playwright test stack declared at the monorepo root (package.json), this enables 100% code coverage claims made by the project.
Granular Feature Packages
Each major capability lives in its own package, so consumers can install only what they need:
| Package | Concern | Source reference |
|---|---|---|
ckeditor5-markdown-gfm | GitHub Flavored Markdown input/output | package.json |
ckeditor5-bookmark | Anchor/bookmark navigation | README.md |
ckeditor5-source-editing | Raw HTML source view | README.md |
ckeditor5-page-break | Print-style page breaks | package.json |
ckeditor5-highlight | Text highlighting | README.md |
ckeditor5-style | Block/inline styles | README.md |
ckeditor5-language | Multi-language text parts | README.md |
All packages are authored in TypeScript and re-export their public API through ./src/index.ts in development, with a compiled ./dist form for publishing (packages/ckeditor5/package.json).
4. Collaboration, Tooling, and Community Notes
The engine implements Operational Transformation for the tree-structured model to enable real-time collaborative editing, with cloud infrastructure and collaboration plugins shipped separately (packages/ckeditor5-engine/README.md).
Several long-running community discussions map directly onto the extension model:
- TypeScript typings (#504): Originally a top-voted request, now resolved — typings ship with every package and are built alongside the JavaScript bundles, accessible via the
typesfield inpublishConfig(packages/ckeditor5/package.json). - Framework integrations such as Next.js (#7376): Frameworks integrate by mounting the editor inside a client component and passing a pre-configured
Editorbuilt from theContextAPI (packages/ckeditor5-core/src/context.ts). - Content drag-and-drop (#2664) and Media embed resizing (#6593): These remain active feature requests that require new plugins hooking into the conversion pipeline and the widget UI; they illustrate how third parties can extend the editor without forking core code.
- Inline-styled output (#1627): Output style is controlled through the data processor layer, the same mechanism used by
ckeditor5-markdown-gfm(packages/ckeditor5-markdown-gfm/package.json).
The release v48.2.0 highlights media embed resizing, which is implemented as a UI plugin layered on top of the existing media embed feature (README.md).
5. Common Failure Modes
- Plugin ordering: Plugins that depend on commands or schema definitions registered by another plugin must list that dependency explicitly, otherwise commands may be unavailable at construction time.
- Schema violations: Because the engine core is schema-less, every plugin that introduces new elements or attributes must register them; missing registrations cause silent data loss on serialization (packages/ckeditor5-engine/README.md).
- Non-browser environments: Code that touches
windowordocumentdirectly (instead of theglobalhelper) will throw in headless Node contexts (packages/ckeditor5-utils/src/dom/global.ts). - Workspace vs. published imports: Inside the monorepo packages reference each other with
workspace:*; mixing these with the public@ckeditor/*names will fail to resolve (packages/ckeditor5-page-break/package.json). - License expectations: All packages are dual-licensed under GPL-2.0-or-later and a commercial CKSource license (packages/ckeditor5-engine/README.md).
See Also
Source: https://github.com/ckeditor/ckeditor5 / Human Manual
Installation, Configuration, and Framework Integration
Related topics: CKEditor 5 Overview and Core Architecture, Framework, Plugins, and Extensibility
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: CKEditor 5 Overview and Core Architecture, Framework, Plugins, and Extensibility
Installation, Configuration, and Framework Integration
CKEditor 5 is a modular, multi-package monorepo that ships a modern JavaScript rich-text editor with MVC architecture, a custom data model, and a virtual DOM, written from scratch in TypeScript. This page documents how to install, configure, and integrate the editor with modern frameworks, drawing directly on the repository's package metadata, plugin contracts, and core utilities.
Repository Layout and Package Model
The repository is a workspace managed with pnpm (or yarn) and Node.js 24+ as declared in the root package.json engines field. The root package, ckeditor5-root, is private and acts only as the development environment; the actual deliverable lives in packages/ckeditor5.
Each feature package, such as @ckeditor/ckeditor5-bookmark or @ckeditor/ckeditor5-page-break, exposes a type: "module" entry that points at TypeScript sources for development and at dist/*.js plus dist/index.d.ts for publishing:
"type": "module",
"main": "./src/index.ts",
"exports": {
".": "./src/index.ts",
"./*": "./*"
},
"publishConfig": {
"main": "./dist/index.js",
"types": "./dist/index.d.ts"
}
Source: packages/ckeditor5-bookmark/package.json:1-30
This dual-entry pattern means consumers can import the editor directly into TypeScript projects and get first-class type definitions without any extra typings package. Community request #504 ("Typings for TypeScript") is therefore resolved out of the box: every workspace package ships its own index.d.ts after build.
Core Plugin Architecture
CKEditor 5 is built around a plugin system. Every feature extends Plugin and declares its dependencies via a static get requires() array, as shown by the image block editor:
public static get requires(): PluginDependenciesOf<[
ImageEditing,
ImageSizeAttributes,
ImageUtils,
ImagePlaceholder,
ClipboardPipeline
]> {
return [
ImageEditing, ImageSizeAttributes, ImageUtils, ImagePlaceholder, ClipboardPipeline
];
}
public static get pluginName() {
return 'ImageBlockEditing' as const;
}
Source: packages/ckeditor5-image/src/image/imageblockediting.ts
The Core package is the architectural backbone. Its package.json (@ckeditor/ckeditor5-core) lists the engine as its main dependency and is described in the documentation as "The core architecture of CKEditor 5" — the place where Editor, Plugin, and Command live. The engine package, in turn, provides the MVC editing pipeline, schema, converters, and the virtual DOM. Source: packages/ckeditor5-core/package.json:1-15
Class Composition with `mix`
Reusable behavior is composed through mixins rather than inheritance. The mix helper in ckeditor5-utils accepts a base Constructor and a mixin interface, returning a new constructor that exposes both:
function MyMixin<Base extends Constructor>( base: Base ): Mixed<Base, MyMixinInterface> {
// ...
}
Source: packages/ckeditor5-utils/src/mix.ts:1-40
Combined with the Constructor<Instance = object> helper type, plugins can stack capabilities (e.g., ObservableMixin, FocusTrackerMixin) without deep inheritance chains — a key configuration pattern when authoring custom plugins.
Configuration and Data Flow
Configuration is delivered to the editor through the config object passed to the editor constructor. The schema layer (editor.model.schema) is where feature plugins declare allowed attributes, as seen in ImageBlockEditing.init():
schema.register( 'imageBlock', {
inheritAllFrom: '$blockObject',
allowAttributes: [ 'alt', 'src', 'srcset' ]
} );
Source: packages/ckeditor5-image/src/image/imageblockediting.ts
This pattern is consistent across the codebase: each feature plugin registers schema items, adds converters for the editing and data pipelines, and exposes commands such as imageTypeBlock. Data flow follows the standard CKEditor 5 pipeline:
flowchart LR A[User Input] --> B[Editing Engine<br/>Virtual DOM] B --> C[Model<br/>Custom Tree] C --> D[Converters] D --> E[Data Pipeline<br/>HTML / Markdown] E --> F[editor.getData] C --> B
The engine layer separates the source of truth (the model) from the rendered DOM, which is what enables features like real-time collaboration and undo/redo. Source: packages/ckeditor5-engine/README.md:1-25
Framework Integration
Because every package is published as native ES modules with TypeScript types, integration with frameworks such as React, Angular, Vue, or Next.js is a matter of dynamic import plus an effect hook. Community issue #7376 ("Next.js integration") was addressed by the new installation methods shipped in v42.0.0, which work with SSR-enabled bundlers out of the box.
The global utility in ckeditor5-utils further eases integration by providing a single, mockable accessor for window and document:
import { global } from 'ckeditor5';
testUtils.sinon.stub( global, 'window', { innerWidth: 10000 } );
Source: packages/ckeditor5-utils/src/dom/global.ts:1-40
The module is wrapped in a try/catch so that loading it in non-DOM environments (e.g., during server-side rendering or in unit tests) does not throw. This is critical for Next.js, where components are pre-rendered on the server before hydration.
Quick-Start Configuration Example
A typical integration configures the editor with a list of plugins, a toolbar definition, and optional data:
import { ClassicEditor, Essentials, Paragraph, Bold, Italic } from 'ckeditor5';
const editor = await ClassicEditor.create( document.querySelector( '#editor' ), {
plugins: [ Essentials, Paragraph, Bold, Italic ],
toolbar: [ 'bold', 'italic' ],
initialData: '<p>Hello world!</p>'
} );
Each named plugin corresponds to a published workspace package (for example, Bold lives in @ckeditor/ckeditor5-basic-styles). The Essentials meta-plugin aggregates Undo, Clipboard, and other universally required features, so consumers rarely need to wire them manually.
Selecting a Distribution
The repository ships three flavors of the editor to match different use cases:
| Distribution | Use case | Package |
|---|---|---|
ckeditor5 (full bundle) | Pre-bundled editor with most features | packages/ckeditor5 |
Individual @ckeditor/ckeditor5-* packages | Tree-shakeable integration into custom builds | packages/ckeditor5-* |
ckeditor5-collaboration and friends | Real-time collaborative editing | External CKEditor packages |
Source: packages/ckeditor5-markdown-gfm/package.json:1-25
For projects that need to ingest or emit Markdown instead of HTML, the @ckeditor/ckeditor5-markdown-gfm package provides a GitHub-Flavored-Markdown data processor that plugs into the same converter pipeline shown above.
Common Failure Modes
- Missing peer dependency: Because the
ckeditor5umbrella package re-exports its sub-packages, importing a feature directly from a deep path (e.g.,ckeditor5/table) requires that the matching sub-package be installed; otherwise bundlers will fail to resolve. - SSR/CSR mismatch: Calling
ClassicEditor.create()during server rendering throws becausewindowanddocumentare not available. Wrap the call in a client-only guard or use the dynamicimport()pattern recommended for Next.js. - Custom data output: A frequent request (#1627) is to make
editor.getData()return inline styles. Because the data pipeline is model-driven, the supported approach is to extend the schema and add a custom converter rather than post-processing the HTML.
See Also
Source: https://github.com/ckeditor/ckeditor5 / Human Manual
Doramagic Pitfall Log
Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
Doramagic Pitfall Log
Found 21 structured pitfall item(s), including 3 high/blocking item(s). Top priority: Maintenance risk - Maintenance risk requires verification.
1. Maintenance risk: Maintenance risk requires verification
- Severity: high
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/ckeditor/ckeditor5/issues/20107
2. Maintenance risk: Maintenance risk requires verification
- Severity: high
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/ckeditor/ckeditor5/issues/18352
3. Maintenance risk: Maintenance risk requires verification
- Severity: high
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/ckeditor/ckeditor5/issues/20196
4. Installation risk: Installation risk requires verification
- Severity: medium
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/ckeditor/ckeditor5/issues/18524
5. Installation risk: Installation risk requires verification
- Severity: medium
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/ckeditor/ckeditor5/issues/19609
6. Installation risk: Installation risk requires verification
- Severity: medium
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/ckeditor/ckeditor5/issues/18547
7. Installation risk: Installation risk requires verification
- Severity: medium
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/ckeditor/ckeditor5/issues/18525
8. Installation risk: Installation risk requires verification
- Severity: medium
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/ckeditor/ckeditor5/issues/18545
9. Installation risk: Installation risk requires verification
- Severity: medium
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/ckeditor/ckeditor5/issues/18522
10. Installation risk: Installation risk requires verification
- Severity: medium
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/ckeditor/ckeditor5/issues/19846
11. Installation risk: Installation risk requires verification
- Severity: medium
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/ckeditor/ckeditor5/issues/5620
12. Installation risk: Installation risk requires verification
- Severity: medium
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/ckeditor/ckeditor5/issues/14724
Source: Doramagic discovery, validation, and Project Pack records
Community Discussion Evidence
These external discussion links are review inputs, not standalone proof that the project is production-ready.
Count of project-level external discussion links exposed on this manual page.
Open the linked issues or discussions before treating the pack as ready for your environment.
Community Discussion Evidence
Doramagic exposes project-level community discussion separately from official documentation. Review these links before using ckeditor5 with real data or production workflows.
- Incorrect order of adjacent markers in output data (follow-up) - github / github_issue
- 📄 Nightly releases changelog - github / github_issue
- Make it simple to extend downcast converters for markers (and other) - github / github_issue
- Image config to overide default image alignment doesnt work - github / github_issue
- Emoji (Mention) tooltip calculates positioning doesn't update after ente - github / github_issue
- Column resize in nested child table. - github / github_issue
- Cancel move effect if element dropped outside of editor - github / github_issue
- Checklist cursor position - github / github_issue
- New item in a to-do list inherits state from the previous one. - github / github_issue
- Fullscreen: Balloon-panel can overlap toolbar for element which is talle - github / github_issue
- Table shrinks when resizing columns in editor with fixed height and scro - github / github_issue
- Cannot add custom button to HeadingButtonUi - github / github_issue
Source: Project Pack community evidence and pitfall evidence