Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
bb269f7
Adding aggregated roots config.
niegowski Mar 9, 2026
68561aa
Added support for multi-root dedicated config.
niegowski Mar 10, 2026
50d9a1a
Some API docs cleaning.
niegowski Mar 10, 2026
c938e54
Add tests for normalizeRootsConfig util.
niegowski Mar 10, 2026
7e5a6f9
Merge branch 'master' into ck/19885
Mati365 Mar 11, 2026
6b2965b
Avoid prototype pollution.
niegowski Mar 11, 2026
ea2be4f
Minor api docs changes related to roots configuration.
Mati365 Mar 11, 2026
2835050
Adjust manual tests.
Mati365 Mar 11, 2026
3124bcd
Adjust more places.
Mati365 Mar 11, 2026
0b0781a
Fix few tests.
Mati365 Mar 11, 2026
0369567
Update guide
Mati365 Mar 11, 2026
d0229cc
Update more docs.
Mati365 Mar 11, 2026
d9a53ed
Adjust paths.
Mati365 Mar 11, 2026
9e6d966
Merge branch 'ck/19885' into ck/19885-docs-fixes
Mati365 Mar 11, 2026
eb4cb4d
Fix path typo.
Mati365 Mar 11, 2026
07cad2b
Merge branch 'ck/19885' into ck/19885-docs-fixes
Mati365 Mar 11, 2026
0f57ed9
Fix few api docs.
Mati365 Mar 11, 2026
b5faac5
Merge branch 'ck/19885' into ck/19885-docs-fixes
Mati365 Mar 11, 2026
1b2c96d
Adjust multiroot editor code snippet
Mati365 Mar 11, 2026
8296538
Move snippets changes to different branch.
Mati365 Mar 11, 2026
46b13f9
Merge branch 'ck/19885' into ck/19885-docs-fixes
Mati365 Mar 11, 2026
d031651
Revert "Move snippets changes to different branch."
Mati365 Mar 11, 2026
bf993b8
Restore config modifications.
Mati365 Mar 11, 2026
631c6f4
Fixed issues with watchdog and multi root editor.
niegowski Mar 11, 2026
616087f
More snippet changes.
Mati365 Mar 12, 2026
5610b03
Merge branch 'ck/19885' into ck/19885-docs-fixes
Mati365 Mar 12, 2026
a05fb7e
Fix indent
Mati365 Mar 12, 2026
ef1dcdf
Fix indent
Mati365 Mar 12, 2026
fadcb04
Fix in the Angular integration.
gorzelinski Mar 12, 2026
4439ee3
Fix in the Next.js integration.
gorzelinski Mar 12, 2026
402d913
Fix in getting and setting data.
gorzelinski Mar 12, 2026
3b1880a
Adjusted the Title plugin to the normalized editor config.
niegowski Mar 12, 2026
02b7720
Removed imports from core in watchdog.
niegowski Mar 12, 2026
a65ae75
Added tests for code coverage.
niegowski Mar 12, 2026
3ed3b7f
Adjust the editor placeholder guide.
gorzelinski Mar 12, 2026
8528fc3
Adjust custom editor creator.
gorzelinski Mar 12, 2026
b7357d8
Adjust the placeholder manual test.
gorzelinski Mar 12, 2026
d5d4aa3
Adjust the custom editor creator guide.
gorzelinski Mar 12, 2026
978692a
Fixed dependencies.
niegowski Mar 12, 2026
4777f9b
Marked optional config option as optional.
niegowski Mar 12, 2026
8190f4c
Fixed invalid test.
niegowski Mar 12, 2026
b891e6d
Updated pnpm-lock files.
niegowski Mar 12, 2026
5a7983e
Merge branch 'master' into ck/19885
niegowski Mar 12, 2026
b4f0204
Merge branch 'ck/19885' into ck/19885-docs-fixes
Mati365 Mar 13, 2026
237720d
Adjust multi root editor to the config change.
gorzelinski Mar 13, 2026
c0d210d
Adjust watchdog to the config changes.
gorzelinski Mar 13, 2026
a985826
Adjust the `RootConfig` interface.
gorzelinski Mar 13, 2026
7fd5d42
Adjust the augmentation interface in multi root editor.
gorzelinski Mar 13, 2026
ea7d252
Fix redundancy.
gorzelinski Mar 13, 2026
f82c56f
Changed modelElement.attributes to modelAttributes root config.
niegowski Mar 14, 2026
f198439
Editable options stored as root attributes to propagate in RTC and RH.
niegowski Mar 14, 2026
cf2fb29
Added tests.
niegowski Mar 14, 2026
c8fa891
Cleanup.
niegowski Mar 14, 2026
4c49bca
Added missing re-exports.
niegowski Mar 14, 2026
048442f
Review fixes.
niegowski Mar 14, 2026
4effe13
Fix invalid module specifier.
niegowski Mar 14, 2026
49c9427
Apply suggestion from @niegowski
Mati365 Mar 16, 2026
b686937
Merge branch 'ck/19885' into ck/19885-docs-fixes
Mati365 Mar 16, 2026
1cc1c3a
Mention the legacy error without a link.
gorzelinski Mar 16, 2026
68bbfb2
Merge branch 'ck/19885' into ck/19885-docs-fixes
gorzelinski Mar 16, 2026
338e10f
Removed a TODO note and added a breaking change note.
niegowski Mar 16, 2026
9260a95
Updated api docs.
niegowski Mar 16, 2026
56768c3
Updated api docs.
niegowski Mar 16, 2026
d696cf7
Added BC note.
niegowski Mar 16, 2026
b618883
Added changelog entries.
niegowski Mar 16, 2026
eb38b5b
Merge branch 'ck/19885' into ck/19885-docs-fixes
Mati365 Mar 16, 2026
3849c94
Merge branch 'master' into ck/19885
Mati365 Mar 16, 2026
2509278
Merge branch 'ck/19885' into ck/19885-docs-fixes
Mati365 Mar 16, 2026
3f5fee1
Adding new signatures to editor constructors.
niegowski Mar 16, 2026
0ee70a4
Removed console.log.
niegowski Mar 16, 2026
d72e58d
adjust normalization of config in tests
Mati365 Mar 17, 2026
1010096
fix incorrect normalization
Mati365 Mar 17, 2026
ee09a8b
Add the section about root changes to the update guide.
gorzelinski Mar 17, 2026
07b8053
Editors should use normalized config to get source elements.
niegowski Mar 17, 2026
adda4e4
The multi-root addRoot should not accept a DOM element.
niegowski Mar 17, 2026
ee8bc9d
Added warning for config.attachTo.
niegowski Mar 17, 2026
18ac0bc
The textarea verification should use normalized config.
niegowski Mar 17, 2026
1d6c694
Added log warning.
niegowski Mar 17, 2026
fba83db
Added tests.
niegowski Mar 17, 2026
b51b3ce
Updated classic test editor.
niegowski Mar 17, 2026
0526aef
Introduced changes to watchdog.
niegowski Mar 17, 2026
7c2cd08
Added tests.
niegowski Mar 18, 2026
522de92
Added test.
niegowski Mar 18, 2026
8447ef7
Replaced invalid test.
niegowski Mar 18, 2026
09dafa3
Fixed bug reported by bugbot.
niegowski Mar 18, 2026
72f8994
The EditorWatchdog.setCreator() should expect config only in config b…
niegowski Mar 18, 2026
7ba9c8e
Merge pull request #19948 from ckeditor/ck/19885-docs-fixes
niegowski Mar 18, 2026
d179646
Removed redundant params normalization.
niegowski Mar 18, 2026
a85d24f
Merge branch 'ck/19885' into ck/19887
niegowski Mar 18, 2026
e47ac69
Updating jsdocs.
niegowski Mar 18, 2026
0f066bf
Updating examples in jsdocs.
niegowski Mar 18, 2026
e50d77b
Apply suggestions from code review.
niegowski Mar 18, 2026
aa135f7
Apply suggestions from code review.
niegowski Mar 18, 2026
23eda2f
Apply suggestions from code review.
niegowski Mar 18, 2026
237d3d4
Apply suggestions from code review.
niegowski Mar 18, 2026
c629429
Apply suggestions from code review.
niegowski Mar 18, 2026
e945b5c
Apply suggestions from code review.
niegowski Mar 18, 2026
764d29a
Apply suggestions from code review.
niegowski Mar 18, 2026
f302a91
Apply suggestions from code review.
niegowski Mar 18, 2026
bda5e06
Apply suggestions from code review.
niegowski Mar 18, 2026
34f0085
Fixed initial data priorities.
niegowski Mar 18, 2026
98306b2
Revert "Fixed initial data priorities."
niegowski Mar 18, 2026
3df9229
Merge branch 'master' into ck/19885
niegowski Mar 18, 2026
4835dd8
Merge branch 'ck/19885' into ck/19887
niegowski Mar 18, 2026
ad79d22
Removed a leftover.
niegowski Mar 18, 2026
14cb397
Merge pull request #19966 from ckeditor/ck/19887
niegowski Mar 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 253 additions & 0 deletions packages/ckeditor5-core/src/editor/editorconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ export interface EditorConfig extends EngineConfig {
* If `config.initialData` is not set when the editor is initialized, the data received in `Editor.create()` call
* will be used to set `config.initialData`. As a result, `initialData` is always set in the editor's config and
* plugins can read and/or modify it during initialization.
*
* **This property has been deprecated and will be removed in the future versions of CKEditor. Please use
* {@link module:core/editor/editorconfig~EditorConfig#root `root.initialData`} or
* {@link module:core/editor/editorconfig~EditorConfig#roots `roots.<rootName>.initialData`} instead.**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When to use the latter? It sounds like we're giving the user an option, while we don't.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PS. I know that root is an alias for roots.main but please do not overcomplicate it for people. The roots option should in practice be used only by the users of the multiroot editor.

*
* @deprecated
*/
initialData?: string | Record<string, string>;

Expand Down Expand Up @@ -537,6 +543,12 @@ export interface EditorConfig extends EngineConfig {
* element passed to the `create()` method.
*
* See the {@glink features/editor-placeholder "Editor placeholder"} guide for more information and live examples.
*
* **This property has been deprecated and will be removed in the future versions of CKEditor. Please use
* {@link module:core/editor/editorconfig~EditorConfig#root `root.placeholder`} or
* {@link module:core/editor/editorconfig~EditorConfig#roots `roots.<rootName>.placeholder`} instead.**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When to use the latter? It sounds like we're giving the user an option, while we don't.

*
* @deprecated
*/
placeholder?: string | Record<string, string>;

Expand Down Expand Up @@ -864,8 +876,243 @@ export interface EditorConfig extends EngineConfig {
* .then( ... )
* .catch( ... );
* ```
*
* **This property has been deprecated and will be removed in the future versions of CKEditor. Please use
* {@link module:core/editor/editorconfig~EditorConfig#root `root.label`} or
* {@link module:core/editor/editorconfig~EditorConfig#roots `roots.<rootName>.label`} instead.**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When to use the latter? It sounds like we're giving the user an option, while we don't.

*
* @deprecated
*/
label?: string | Record<string, string>;

/**
* The root configuration options for the default `main` root.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a sufficient documentation in this place. When you visit the API docs and land on https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editorconfig.html#interface-EditorConfig you will only see these two paragraphs. But this is by far one of the most important configuration options. Thus, it must contain proper examples of a simple (typical) use and fuller case.

*
* This option is an alias for `config.roots.main`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if both are configured? Maybe add something like "...and will be ignored if config.roots is defined"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I see you throw error. Document that.

*/
root?: RootConfig;

/**
* The root configuration options grouped by the root name.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be more thorough. In the case of which editor type does this option make sense? Which option to use when using a typical editor (link to config.root).

*
* ```ts
* ClassicEditor
* .create( document.querySelector( '#editor' ), {
* roots: {
* main: {
* initialData: '<p>Hello world!</p>',
* placeholder: 'Type some text...',
* label: 'Main content'
* }
* }
* } );
* ```
*/
roots?: Record<string, RootConfig>;
}

/**
* Configuration for a single editor root. It is used in {@link module:core/editor/editorconfig~EditorConfig#root `EditorConfig#root`} and
* {@link module:core/editor/editorconfig~EditorConfig#roots `EditorConfig#roots.<rootName>`}.
*
* **Note**: If your editor implementation uses only a single root, you can use `config.root` to set the root configuration instead of
* `config.roots.main`.
*/
export interface RootConfig {

/**
* The initial editor data to be used instead of the provided element's HTML content.
Copy link
Member

@Reinmar Reinmar Mar 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What element? It's explained later, but let's limit the cognitive load at this point.

*
* ```ts
* ClassicEditor
* .create( document.querySelector( '#editor' ), {
* root: {
* initialData: '<h2>Initial data</h2><p>Foo bar.</p>'
* }
* } )
* .then( ... )
* .catch( ... );
* ```
*
* By default, the editor is initialized with the content of the element on which this editor is initialized.
* This configuration option lets you override this behavior and pass different initial data.
* It is especially useful if it is difficult for your integration to put the data inside the HTML element.
*
* If your editor implementation uses multiple roots, you should provide config for roots individually:
*
* ```ts
* MultiRootEditor.create(
* // Roots for the editor:
* {
* header: document.querySelector( '#header' ),
* content: document.querySelector( '#content' ),
* leftSide: document.querySelector( '#left-side' ),
* rightSide: document.querySelector( '#right-side' )
* },
* // Config:
* {
* roots: {
* header: {
* initialData: '<p>Content for header part.</p>'
* },
* content: {
* initialData: '<p>Content for main part.</p>'
* },
* leftSide: {
* initialData: '<p>Content for left-side box.</p>'
* },
* rightSide: {
* initialData: '<p>Content for right-side box.</p>'
* }
* }
* }
* )
* .then( ... )
* .catch( ... );
* ```
* See also {@link module:core/editor/editor~Editor.create Editor.create()} documentation for the editor implementation which you use.
*
* **Note:** If initial data is passed to `Editor.create()` in the first parameter (instead of a DOM element), and,
Copy link
Member

@Reinmar Reinmar Mar 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to mention this?

* at the same time, `config.initialData` is set, an error will be thrown as those two options exclude themselves.
*
* If `config.root.initialData` is not set when the editor is initialized, the data received in `Editor.create()` call
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that you mean the data from the first parameter? It is not clear.

* will be used to set `config.roots.main.initialData`. As a result, `initialData` is always set in the editor's config and
* plugins can read and/or modify it during initialization. TODO breaking change - the updated initialData changes location
*/
initialData?: string;

/**
* Specifies the text displayed in the editor when there is no content (editor is empty). It is intended to
* help users locate the editor in the application (form) and prompt them to input the content. Work similarly
* as to the native DOM
* [`placeholder` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#The_placeholder_attribute)
* used by inputs.
*
* ```ts
* ClassicEditor
* .create( document.querySelector( '#editor' ), {
* root: {
* placeholder: 'Type some text...'
* }
* } )
* .then( ... )
* .catch( ... );
* ```
*
* If your editor implementation uses multiple roots, you should provide config for roots individually:
*
* ```ts
* MultiRootEditor.create(
* // Roots for the editor:
* {
* header: document.querySelector( '#header' ),
* content: document.querySelector( '#content' ),
* leftSide: document.querySelector( '#left-side' ),
* rightSide: document.querySelector( '#right-side' )
* },
* // Config:
* {
* roots: {
* header: {
* placeholder: 'Type header...'
* },
* content: {
* placeholder: 'Type content...'
* },
* leftSide: {
* placeholder: 'Type left-side...'
* },
* rightSide: {
* placeholder: 'Type right-side...'
* }
* }
* }
* )
* .then( ... )
* .catch( ... );
* ```
*
* The placeholder text is displayed as a pseudo–element of an empty paragraph in the editor content.
* The paragraph has the `.ck-placeholder` CSS class and the `data-placeholder` attribute.
*
* ```html
* <p data-placeholder="Type some text..." class="ck-placeholder">
* ::before
* </p>
* ```
*
* **Note**: Placeholder text can also be set using the `placeholder` attribute if a `<textarea>` is passed to
* the `create()` method, e.g. {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`}.
*
* **Note**: This configuration has precedence over the value of the `placeholder` attribute of a `<textarea>`
* element passed to the `create()` method.
*
* See the {@glink features/editor-placeholder "Editor placeholder"} guide for more information and live examples.
*/
placeholder?: string;

/**
* Label text for the `aria-label` attribute set on editor editing area. Used by assistive technologies
* to tell apart multiple editor instances (editing areas) on the page. If not set, a default
* "Rich Text Editor. Editing area [name of the area]" is used instead.
Comment on lines +1098 to +1100
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In AI we are looking forward to use this label property to assign metadata to particular roots or editors, so that the user can ask in natural language to make changes in particular root (e.g. "translate heading").

Hence, I propose to change description for this property. It should be more general, like,

"Label which briefly describes this editing area.

It is used to for aria-label attribute set on editing area (...)

It can be also used by other features when referring to this area."

You can consult with @oleq this API doc.

*
* ```ts
* ClassicEditor
* .create( document.querySelector( '#editor' ), {
* root: {
* label: 'My editor'
* }
* } )
* .then( ... )
* .catch( ... );
* ```
*
* If your editor implementation uses multiple roots, you should provide config for roots individually:
*
* ```ts
* MultiRootEditor.create(
* // Roots for the editor:
* {
* header: document.querySelector( '#header' ),
* content: document.querySelector( '#content' ),
* leftSide: document.querySelector( '#left-side' ),
* rightSide: document.querySelector( '#right-side' )
* },
* // Config:
* {
* roots: {
* header: {
* label: 'Header label'
* },
* content: {
* label: 'Content label'
* },
* leftSide: {
* label: 'Left side label'
* },
* rightSide: {
* label: 'Right side label'
* }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use "label" word in these examples. Instead use "Article header", "Article main content", "Side-quote", "Related links".

* }
* }
* )
* .then( ... )
* .catch( ... );
* ```
*/
label?: string;
}

/**
* Configuration of a root element of the editor. It is used in {@link module:core/editor/editorconfig~EditorConfig#root `config.root`} and
* {@link module:core/editor/editorconfig~EditorConfig#roots `config.roots.<rootName>`} to specify details of the model root element.
*/
export interface RootModelElementConfig {

/**
* TODO This will be used later to specify the name of the model element which will be used as a root. For now, it is always `'$root'`.
*/
name?: string;
}

/**
Expand All @@ -875,6 +1122,12 @@ export interface EditorConfig extends EngineConfig {
* @error editor-create-initial-data
*/

/**
* The `config.initialData` option cannot be used together with the `config.root.initialData` or `config.roots.main.initialData`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More context needed. Which option to use?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, you can make these links to the API docs.

*
* @error editor-create-roots-initial-data
*/

/**
* The configuration of the editor language.
*
Expand Down
Loading