#14724·ckeditor5

Nightly releases changelog

Author: CKEditorBotCreated Aug 2, 2023Updated Sep 18, 2026
Labelstype:improvement

Below you can find the changelog for the latest CKEditor 5 nightly release (0.0.0-nightly-20260917.0).

These entries are generated automatically based on the files stored in the .changelog/ directory. As a result, some items may be unclear or difficult to interpret. We apologize for any inconvenience.

The changelog is built starting from the latest stable release (48.5.1), using it as a reference point for collecting changes.

To learn more about CKEditor 5 nightly releases, see #14502.


0.0.0-nightly-20260917.0 (September 18, 2026)

MAJOR BREAKING CHANGES ℹ️

  • ckeditor5, core, utils: The @ckeditor/ckeditor5-watchdog package was removed, and with it the automatic restart of a crashed editor. An editor that crashes now stays as it is, with its content and its undo history, instead of being rebuilt from the data it had before.

    • The EditorWatchdog and ContextWatchdog classes are gone, as are the Watchdog base class and the WatchdogConfig type. They are no longer re-exported from ckeditor5.
    • The Editor.EditorWatchdog and Editor.ContextWatchdog static fields were removed from every editor class.
    • ActionsRecorder is not affected. It only lived in that package and now ships from @ckeditor/ckeditor5-core.

    Use onEditorError() to observe errors instead. It reports the error together with the editor or context it came from, and returns a function that unregisters the callback. Where the editor class is all you have — a framework integration, above all — the same function is reachable as Editor.onEditorError() and Context.onEditorError().

    javascript
    import { onEditorError } from 'ckeditor5';
    
    const off = onEditorError( ( { error, source } ) => {
        console.error( 'An error escaped', source, error );
    } );

    If you used ContextWatchdog to share a context between editors, create the Context yourself and pass it in the editor configuration. The context is then yours to destroy when you are done with it, which ContextWatchdog used to do for you.

    javascript
    const context = await Context.create( contextConfig );
    
    const editor = await ClassicEditor.create( { context, /* ... */ } );

    Integrators who relied on the restart should handle the reported errors themselves — reload the editor, tell the user, or report to their error tracker.

  • ckeditor5, ui: The UI theme is now built on a three-layer system of CSS custom properties, replacing the previous flat set of theme variables with more granular, predictable customization points. Closes #19910.

    The layers are:

    1. Foundation primitives, such as the spacing, radius, and color scales.
    2. Semantic design roles shared across components, such as control padding and surface radius.
    3. Per-component override points, such as the button or dialog tokens.

    Custom themes that read the previous variables keep working, as the legacy names are preserved as backward-compatible aliases. The breaking surface is narrower: some legacy hooks were removed outright, and overriding a foundation or legacy variable no longer necessarily cascades through the semantic and component layers, so scoped overrides should target the component token closest to the property. See the theme token naming guide in the CKEditor 5 documentation for the layer model and the recommended override points.

  • ckeditor5, ui: The editor now ships a refreshed, more modern default look, expressed entirely through the new tiered design tokens. Every integration that uses the default theme gets the new appearance. Closes #20235.

    The previous look remains available as an opt-in legacy theme - a single stylesheet you load - so integrations that prefer the old appearance can keep it with a one-line change.

    Some of the refreshed styles also apply to .ck-content, so already-published documents render slightly differently - for example comment and suggestion markers, block quotes, code blocks, and horizontal lines. Rollback snippets that restore the previous content colors ship with this release.

    Custom themes are largely unaffected: CSS that reads the previous token names keeps working through backward-compatible aliases. Overriding a legacy name to re-skin the editor's internals is the part that changes - use the new tokens or the legacy theme instead. See the theme migration guide for the upgrade path.

  • core: ActionsRecorder moved from @ckeditor/ckeditor5-watchdog to @ckeditor/ckeditor5-core. It was never part of the Watchdog — it only lived in that package — and the package is removed in this release.

    Nothing changes for anyone importing from ckeditor5, which re-exports @ckeditor/ckeditor5-core. Code importing from the Watchdog package directly has to change:

    javascript
    // Before.
    import { ActionsRecorder } from '@ckeditor/ckeditor5-watchdog';
    
    // After.
    import { ActionsRecorder } from '@ckeditor/ckeditor5-core';

    The ActionsRecorderConfig, ActionsRecorderEntry, ActionsRecorderEntryEditorSnapshot, ActionsRecorderErrorCallback, ActionsRecorderFilterCallback and ActionsRecorderMaxEntriesCallback types moved with it, as did the config.actionsRecorder declaration, so the configuration option keeps its typing.

  • ui: The TooltipManager lifecycle has changed. It is no longer instantiated per editor with new TooltipManager( editor ), and its constructor is now private: obtain the shared instance through the new static TooltipManager.for( locale ) method, which reference counts its holders, and call release() on it, instead of destroy( editor ), once a holder no longer needs it. As before, there is a single shared instance per page, so editor.ui.tooltipManager is the same object for every editor, and the Locale of the first caller is the one it uses. See #3891.

  • ui: The BodyCollection#detachFromDom() method has been renamed to BodyCollection#destroy(). Its behavior is unchanged: it destroys the collection's views and removes their container from the DOM. The new name makes clear that this is a permanent teardown, distinct from the new and reversible BodyCollection#unmountFromDom() method. Replace every detachFromDom() call with destroy(). See #3891.

  • All packages and CDN builds now target ES2023, up from ES2022.

  • The distributed stylesheets now use native CSS nesting instead of flattened selectors. Tools that post-process the CKEditor 5 CSS must support nesting. Some PostCSS configurations and minifiers are older than CSS nesting. If your build uses one, add a nesting transform to it.

MINOR BREAKING CHANGES ℹ️

  • block-quote, code-block: Block quotes and code blocks now use lighter border and background colors. As these are content styles, the change also affects already-published content. To restore the previous colors, add this CSS after the editor content styles: See #19910.

    css
    .ck-content blockquote {
        border-left: solid 5px hsl(0, 0%, 80%);
    }
    
    .ck-content[dir="rtl"] blockquote {
        border-right: solid 5px hsl(0, 0%, 80%);
    }
    
    .ck-content pre {
        background: hsla(0, 0%, 78%, 0.3);
        border: 1px solid hsl(0, 0%, 77%);
    }
  • export-pdf, export-word: The converterOptions.extra_http_headers option no longer accepts an object keyed by the domain. Pass an array of { domain, headers } entries instead.

    javascript
    // Before.
    converterOptions: {
        extra_http_headers: {
            'https://medias.example.org/': { authorization: 'Bearer xxx' }
        }
    }
    
    // After.
    converterOptions: {
        extra_http_headers: [
            { domain: 'https://medias.example.org/', headers: { authorization: 'Bearer xxx' } }
        ]
    }

    The object form never worked in the editor configuration, because configuration keys are split on every . character, so this affects only integrations passing the converter options directly to the exportPdf or exportWord command.

  • comments, track-changes: The default colors of comment highlights and suggestion insertion/deletion markers in the editing content have been refreshed to align with the new editor theme. Because these styles also apply to published .ck-content, existing documents render with the new colors. To restore the previous appearance, override the --ck-comment-marker-* and --ck-suggestion-marker-* custom properties (see the content styles rollback snippet).

  • fullscreen, ui: Every editor stylesheet now declares its CSS variables on both :root and :host, so overriding a variable on :root no longer affects an editor inside a shadow root. Override it on the shadow host element instead, and declare the variables of a custom stylesheet on both selectors. See the "Styles inside a shadow DOM" section of the CSS guide. See #3891.

    The few rules that have to reach the light DOM are no longer shipped in the theme stylesheets. They are technical classes such as ck-fullscreen-scroll-locked, which locks the page scroll, and they are adopted into the document at runtime instead, so overriding one of them may need higher specificity than before.

  • engine: The ViewRenderer#domDocuments property has been removed. A set of documents can no longer describe where an editor renders, because an editing root may live in a shadow root instead. The renderer tracks the editing root elements themselves now, in a private property, and there is no public replacement. See #3891.

  • fullscreen: The default container of the fullscreen mode has changed. When config.fullscreen.container is not set, the fullscreen mode is mounted in the shared config.ui.overlayContainer, if there is one, and otherwise in the shadow root the editor lives in. It falls back to the <body> element, which used to be the only default, when there is neither. An explicitly configured container is still honored. See #3891.

    The option is also no longer given a default value internally, so editor.config.get( 'fullscreen.container' ) returns undefined instead of the <body> element when the integrator did not set it.

    Custom CSS may need updating: the wrapper of a fullscreen mode that fills an integrator-provided container is marked with the ck-fullscreen__main-wrapper_custom-container class now.

  • horizontal-line: Horizontal lines now use a lighter background color. As this is a content style, the change also affects already-published content. To restore the previous color, add this CSS after the editor content styles: See #19910.

    css
    .ck-content hr {
        background: hsl(0, 0%, 87%);
    }
  • ui: The editor's body collection (floating user interface such as balloons, dialogs, and tooltips) is no longer attached to the DOM during editor creation. It is attached once the editor's editing root is connected to the document, and .ck-body-wrapper is no longer a single shared element: there is one wrapper per mount target, so an editor in a shadow root or with a configured config.ui.overlayContainer gets a wrapper of its own. See #3891.

    For an editor created on a detached element, .ck-body-wrapper is therefore not present in the DOM immediately after Editor.create() resolves. Code that located it that way, for example through document.querySelector( '.ck-body-wrapper' ), should use editor.ui.view.body.bodyCollectionContainer instead. That element is created on demand and is available even before the collection is attached to the DOM.

  • ui: The clickOutsideHandler() utility function no longer accepts the listenerOptions option, so the priority and the capture mode of its listener can no longer be configured. Remove the option from the call. The function needs those settings for itself: to detect a click inside a context element that lives in a shadow root, it combines its listener on the document with listeners on the shadow roots of the context elements it is given. See #3891.

  • uploadcare: To support an editor placed inside a shadow root, the Uploadcare uc-config and uc-upload-ctx-provider web components are no longer appended to document.body. They are added to the editor's body collection instead, so they are rendered wherever the editor's floating user interface is mounted. The UploadcareEditing#configElement and UploadcareEditing#ctxElement properties are unchanged and remain the way to access them.

  • utils: The getCommonAncestor() DOM utility function has been removed from the ckeditor5-utils package. It walked parentNode chains, which stop at a shadow boundary, so it could not answer correctly for nodes inside a shadow root. To find the lowest common ancestor of two DOM nodes, walk their ancestors with getParentNode() and compare the chains, or use the model and view getCommonAncestor() methods when working with the editor tree. See #3891.

  • utils: The getPositionedAncestor() DOM utility function now returns null for an element that is not connected to a document, where it previously required only that the element had a parent. See #3891.

Features

  • core, fullscreen, ui: Introduced the config.ui.overlayContainer option: the element or shadow root that hosts the editor's floating user interface (balloons, dialogs, and tooltips). Point it at a container of your own when the editor lives inside a shadow root. The editor stylesheets have to be adopted into that container — see the "Styles inside a shadow DOM" section of the CSS guide. See #3891, #5319.

    The config.fullscreen.container option accepts a shadow root as well now.

  • ui, utils: Introduced the public API behind shadow DOM support, for features and integrations that resolve DOM access themselves: the ShadowRootRegistry and OverlayHost classes, the ShadowSelection class together with the getSelection() utility that returns it, the EditorUI#shadowRootRegistry property, and the mounting API of BodyCollection, whose attachToDom() method now accepts an element or a shadow root. See #3891.

    They come with shadow-aware replacements for the plain DOM traversal and hit-testing helpers, such as getParentNode(), containsNode(), getActiveElement() and getElementFromPoint(). See the API documentation of the ckeditor5-utils package for the full list.

  • comments, real-time-collaboration: Introduced the config.sidebar.overlayContainer and config.presenceList.overlayContainer options: the element or shadow root that hosts the floating annotation balloon of the narrow sidebar and the floating presence list dropdown. Set one when the feature runs inside a shadow root, or when its own container clips the floating user interface; otherwise the shared config.ui.overlayContainer is used, if there is one.

  • ckeditor5: The editor can now be created inside a shadow root, open or closed: selection, focus, positioning, scrolling, drag and drop, and the floating user interface all work there. The premium features work in a shadow root as well. Closes #3891.

    Because a shadow root is a separate styling boundary, the editor stylesheets have to be loaded into every root that holds editor user interface, and CSS variables have to be overridden on the shadow host rather than on :root. See the "Styles inside a shadow DOM" section of the CSS guide.

  • ai: The AI Chat and the AI Review Mode now display a loading skeleton during initialization instead of an empty panel.

  • ai: The AI agent now understands the document root it works on. It knows whether the root accepts inline content only and what element hosts it. The agent is also aware of the soft break (Shift+Enter) support in the editor.

  • core: Editor errors can now be observed with the onEditorError() function. It reports errors that escape an editor, together with the editor or context they came from, and returns a function that unregisters the callback. It observes rather than intercepts: nothing is restarted, no editor data is kept or restored, and a reported error still reaches the console exactly as it would with no callback registered. This is the replacement for the Watchdog, which is removed in this major release.

  • ui: The body collection into which the shared tooltip balloon is placed can be chosen now, through th