The easy questions to answer: Why?
- Why switch from CKEditor 4?
- It’s approaching its end-of-life in 2023.
- Why CKEditor 5 and not something else?
- Successful past collaboration, healthy project, clearly significantly better than its predecessor, and also: time constraint. See the core policy issue where this was decided.
- Why now?
- The CKEditor 5 module needs to be stable in the last Drupal 9 minor if we want to be able to deprecate CKEditor 4 (
ckeditor.module) before Drupal 10, so we can remove CKEditor 4 in Drupal 10.
Biggest challenge: Frictionless upgrade path
For Drupal 9 users, the transition must be a simple, painless process to switch from CKEditor 4 to 5 using nothing more than the UI.
For Drupal 10 users, when ckeditor.module is dropped from Drupal core, the result must be exactly the same as if they used the UI.
In both cases, the automatically generated CKEditor 5 configuration must be:
- Correct (result in a working CKEditor 5 instance)
- Accurate (match the CKEditor 4 configuration as closely as possible, and ensure all HTML tags allowed actually work more about that later)
- Actionable (whenever there is functionality that cannot be migrated automatically, we require precise error messages that allow the user to efficiently investigate potential solutions)
To achieve that, we need a detailed automatic analysis of the “before” (CKEditor 4 + text format configuration) and “after” (CKEditor 5 + text format configuration).
Biggest risk: Data loss
Imagine switching from CKEditor 4 to 5 and noticing that certain content either:
- bad: does not appear anymore in the text editor
- worse: did appear in the text editor, but does not appear anymore in the output after having fixed a typo in CKEditor 5
This is a real risk, because CKEditor 4 and 5 have a different architecture.
CKEditor 4 used browsers’ APIs, so it automatically supported every HTML tag, because browsers support those. This caused cross-browser compatibility issues and maintenance difficulties (since different browsers have different features and bugs).
CKEditor 5 reimplements many low-level APIs in JavaScript. This simplifies their code, makes it easier to test, and makes for a more reliable end result. However, this adds challenges for Drupal because CKEditor 5 does not support every HTML tag by default.
Support for Full HTML
A few months ago, CKSource released a plugin called General HTML Support. This allows us to let CKEditor 5 render arbitrary HTML, but not to edit arbitrary HTML.
The Drupal CKEditor 5 module uses this to support the Full HTML
use case: #3216021: Automatically use CKE5's General HTML Support feature on text formats without any TYPE_HTML_RESTRICTOR filter + add `sourceEditing` button.
Tags unsupported by CKEditor 5
Drupal allows restricting allowed tags to an arbitrary set of tags, while CKEditor 5 only supports a subset of HTML 5 tags. For example, Drupal allows <dl> <dt> <dd> by default in Basic HTML
, but CKEditor 5 does not support them.
To address this, the CKEditor 5 Drupal module allows configuring additional “manually editable tags” when using the “Source Editing” button (“View Source” in CKEditor 4), so we can track explicitly which tags and attributes are editable only by editing the HTML source. These tags will then work similarly to how they do in CKEditor 4 and Drupal 9 (as they already did not have buttons available in CKEditor 4).
Biggest win: Massively improved toolbar configuration UX
Also see the “Plugin developer DX” section below.
We need excellent user experience when content editors create a new text format and use CKEditor 5, but also when they switch to and modify CKEditor 5’s configuration.
An essential usability feature of CKEditor 4 is that the text format configuration was kept in sync with the CKEditor configuration. CKEditor 4 used a hidden CKEditor 4 instance in the toolbar configuration UI to get metadata, which then updated filter_html’s “Allowed HTML tags” form field with JavaScript. 🙃😱 This was brittle and buggy, especially following #2549077: Allow the "Limit allowed HTML tags" filter to also restrict HTML attributes, and only allow a small whitelist of attributes by default. CKEditor 4 also has no protection against enabling filters that conflict with it! Related bug reports:
- #2710427: Broken "Allowed Tags" updating: after all values for an attribute are allowed, it should not be overridden to allow only certain attribute values
- #3217732: filterStatus behavior can't find settings markup after AJAX update
- #2689083: Unidirectional editor configuration -> filter settings syncing doesn't respect table child tags
- #2567801: Deprecate core/modules/editor/js/editor.admin.js JS APIs in Drupal 10, for removal in Drupal 11
- #1933896: Prevent enabling a text editor if a text format has one or more FILTER_TYPE_MARKUP_LANGUAGE filters enabled
All of that is solved in CKEditor 5.
As a site builder, you get real-time validation errors:


Biggest change: No Drupal dialogs in CKEditor anymore
There are no longer Drupal-owned dialog forms to add/edit links or images, which is a usability and maintainability improvement, but will require certain contrib modules change their implementation. See: #3231341: Deprecate EditorLinkDialog, EditorImageDialog and EditorMediaDialog in Drupal 10.1 for removal in Drupal 11

Architecture
Plugin developer DX: less PHP (or even no PHP), more YAML/JS
Plugin definitions require little Drupal/PHP knowledge with clearly delineated ckeditor5 and drupal sections. There are helpful messages when the plugin definition does not work.
With CKEditor 4, a JavaScript developer would also need to learn a lot about PHP and Drupal just to get their (custom or publicly available) CKEditor plugin working in Drupal. With CKEditor 5 in Drupal, that same JavaScript developer would have to learn almost nothing about Drupal and only would need to rely on CKEditor's API documentation.
This is the most minimal valid CKEditor 5 plugin definition:
MODULE_NAME_marquee:
ckeditor5:
plugins: [PACKAGE.CLASS]
drupal:
label: Marquee
elements:
- <marquee>
Validation constraints for config
The frictionless upgrade path requires metadata about CKEditor 5 plugins (because those are written in JS, and we cannot automatically infer that metadata from PHP code) and their functionality. This metadata is used for validation (for both the upgrade path and the configuration UI), in addition to generating a CKEditor 5 configuration that supports a given set of HTML tags (as mentioned earlier).
This means that the logical way to implement validation is at the configuration entity level. Drupal 8 and 9 core only include limited use of config validation. So this means that CKEditor 5 also has had to solve reusing config schema validation constraints in a form-based UI. See: #3231342: [PP-2] Introduce ConfigEntityForm to standardize use of validation constraints for config entities.
CKEditor 5’s validation constraints fall in two buckets:
- Fundamental compatibility between a configured CKEditor 5 and the associated text format
-
- A text format must not use any
FilterInterface::TYPE_MARKUP_LANGUAGEfilters as these indicate a custom markup language (like Markdown) rather than HTML. <p>and<br>must be allowed — without them, CKEditor 5 cannot function correctly (nor can CKEditor 4).- The HTML allowed by the text format’s HTML filter configuration must exactly match the HTML that can be generated by the current CKEditor 5 configuration. We compare the HTML restrictions of a text format with
FilterFormatInterface::getHtmlRestrictions()for thedrupal.elementsvalues of all enabled plugins in CKEditor 5.
- A text format must not use any
- Valid CKEditor 5 configuration
-
It is validated that:
- All toolbar items in the configuration actually exist. (Uses the
drupal.toolbar_itemsentry in the metadata example above.) - All enabled plugins that are configurable actually have configuration.
- All “Manually editable tags” added to the “Source Editing” plugin’s configuration are a) valid expressions, b) not present in any of the enabled plugins (illustrated in the screenshot below), c) not present in any of the available plugins.
Strict config schema conformance is required.
- All toolbar items in the configuration actually exist. (Uses the
Many of these validation constraints are impossible to violate when using the UI, but migrations are risky, and the constraints help ensure that both config exports and the migration path are correct.
Note: The “fundamental compatibility” validation constraint needs to validate fundamental compatibility between an Editor config entity and its associated FilterFormat config entity.
These are currently two distinct pieces of configuration (merging them would simplify things a lot: #3231354: [PP-2] [META] Discuss: merge the Editor config entity into the FilterFormat config entity). Since validation constraints can never span multiple entities, we had to work around that limitation: \Drupal\ckeditor5\Plugin\Editor\CKEditor5::validatePair().
Smart Default Settings
When enabled, CKEditor 5 generates smart default settings based on:
- The old CKEditor 4 configuration, if this text format/editor was using it. The toolbar button order and grouping are retained, as is plugin configuration.
- A new group of buttons is added to make the exact HTML restrictions of this text format (
FilterFormatInterface::getHTMLRestrictions()) match the pre-configured HTML precisely.
So you go from this default “Basic HTML” text format in Drupal 8|9:

To this automatically generated equivalent for CKEditor 5 in Drupal 9|10, with messages explaining what happened:

Toolbar configuration UX
Configuring the CKEditor toolbar must have a simple and fully accessible user experience.
Using the richer available metadata (see the drupal.elements metadata above!), we can:
- Automatically generate a sensible CKEditor 5 configuration, based on both the old CKEditor 4 configuration (if any) and the set of allowed HTML tags!
- Guarantee that it is a valid configuration and that it works.
(We challenge you to break it: even the “Restricted HTML” text format will give you helpful warnings that you need to remove the the \Drupal\filter\Plugin\FilterInterface::TYPE_MARKUP_LANGUAGE type filters for it to be possible to use CKEditor 5).
We also reimplemented the drag-and-drop toolbar configuration UX people used to love for CKEditor 4. Ourc CKEditor 5 implementation of this is less brittle than the jQuery code in core/modules/ckeditor/js/ckeditor.admin.es6.js, which came with a hidden CKEditor 4 instance to get the necessary metadata. It’s a tiny decoupled JS app.
Dependency evaluation
CKEditor 5 and the required tooling included as part of the integration require a total of 390 packages as a dependency. These are listed on this file.
ckeditor5, ckeditor5-dev-utils
- Maintainership of the package: CKEditor 5 is maintained professionally by CKSource.
- Security policies of the package: Security policies are documented in the repository.
- Expected release and support cycles: Major releases are shipped every couple of months. Minor releases are shipped more frequently. Only one major release is supported at once. Note that CKEditor 5 is not following semver. Their versioning policy mention that minor releases could include "minor" BC breaking changes.
- Code quality: CKEditor 5 code quality is excellent and the project has very good test coverage.
- Other dependencies it would add, if any: many additional dependencies
- Maintainership of the package
These packages are maintained by the webpack community. Most of the core team members and contributors in the ecosystem do the work in their free time. However, they have pretty solid funding on Open Collective. - Security policies of the package: Security policies are documented in the Webpack repository.
- Expected release and support cycles: Major releases are happening only every few years. Minor and patch releases are coming at a steady pace. I couldn't find whether Webpack 4.0.0 (the previous major release) is still supported. However, they supported it for at least 6 months since the release of Webpack 5.0.0.
- Code quality: We haven't had the need to evaluate Webpack code base because they have very solid documentation, and it has worked out of the box without any issues for all of our use cases.
- Other dependencies it would add, if any: many additional dev dependencies.
- Maintainership of the package: it is partnered with Tidelift, has multiple maintainers, many of whom are visibly active on the most recent page of commit history. The openbase stats suggest the library is frequently attended. In an informal review of open issues (18% of total issues filed remain open), none of the ones that have been open for more than a few weeks appear pressing. Many of these are feature requests or performance improvements. Issues that require prompt turnaround are attended to properly.
- Security policies of the package: jsdom has Tidelift as their security contact, and reports are made directly to Tidelift. The specifics of Tidelift’s policy cover most Drupal-relevant concerns. The report process is confidential and security releases are carefully coordinated. Security updates are limited to the current version: A maintainer confirmed "No previous releases are supported. As a volunteer project, we only ever support the latest-released version. No backports will be performed."
- Expected release and support cycles: No official release cycles, but commits and releases are frequent (but not unexpectedly so - it’s a familiar frequency for popular modern JS libraries) up to 3 major releases can happen in a year. As confirmed by a project maintainer only the current release is supported.
- Code quality: code is quite readable, eslint ruleset extends a maintainers already extensive config, the test coverage is extensive
- Other dependencies: Yes, but jsdom is itself a dev dependency of Drupal and not present in runtime so the following are listed for reference but not subjected to individual dependency evaluations:
"dependencies": { "abab": "^2.0.5", "acorn": "^8.5.0", "acorn-globals": "^6.0.0", "cssom": "^0.5.0", "cssstyle": "^2.3.0", "data-urls": "^3.0.1", "decimal.js": "^10.3.1", "domexception": "^4.0.0", "escodegen": "^2.0.0", "form-data": "^4.0.0", "html-encoding-sniffer": "^3.0.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.0", "parse5": "6.0.1", "saxes": "^5.0.1", "symbol-tree": "^3.2.4", "tough-cookie": "^4.0.0", "w3c-hr-time": "^1.0.2", "w3c-xmlserializer": "^3.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^2.0.0", "whatwg-mimetype": "^3.0.0", "whatwg-url": "^10.0.0", "ws": "^8.2.3", "xml-name-validator": "^4.0.0" },
webpack, webpack-cli, raw-loader, terser-webpack-plugin
JSDOM
Provides the ability to use Nightwatch for JavaScript unit testing.
Roadmap to stable
| Comment | File | Size | Author |
|---|---|---|---|
| #87 | interdiff.txt | 1.71 KB | bnjmnm |
| #87 | 3231364-87.patch | 2.85 MB | bnjmnm |
| #86 | interdiff.txt | 1.22 KB | lauriii |
| #86 | ckeditor5-86.patch | 2.86 MB | lauriii |
| #85 | ckeditor5-82.patch | 2.85 MB | wim leers |
Comments
Comment #3
wim leersThis represents months and months of work by many wonderful people in https://www.drupal.org/project/ckeditor5! 😊😊
It also is in no small part thanks to the wonderful people at https://ckeditor.com/ — without whom this would not be possible. Special thanks to @Reinmar for always making time for us!
Comment #4
wim leers(FYI: the generating of this patch is automated — see #3227826: Preparation for moving CKEditor 5 to core.)
Comment #15
xjmComment #18
xjmComment #19
ghost of drupal pastWhile this is lovely, reading
made me wonder how will media library and entity embed fare. The answer is in #3201824: Roadmap to core. The most important parts of media/media library apparently are already ready.
Comment #20
wim leersClearly it'd have been wiser to first open a test-only issue to first get the patch green. But we've been developing with Drupal core's
core/scripts/dev/commit-code-check.shrunning for us (patched, of course, since it only works for Drupal core). That made us think it'd work on the first try. Clearly not 🙈😅This fixes the cspell violations, and a bunch of other test failures that we found by temporarily disabling the core commit checks. We still expect this to fail, because this introduces one big change: instead of keeping the CKEditor 5 build in
core/modules/ckeditor5/js/…, we move it tocore/assets/vendor/…— which exempts it from many checks. Let's see if I got that right 🤞 (That also explains the huge interdiff.)Built using #3227826-24: Preparation for moving CKEditor 5 to core, using CKEditor 5 module commit
8a8c4580417427d7644f66e218a0e7cc677f4cdd. (The patch in #2 was using commitf4906174b1d0fdd394a1648b35179c19019834a4.)Comment #21
daffie commentedTestbot is not happy.
Comment #23
wim leersTwo
*.es6.jscomplaints remained. Fixed.Built using #3227826-26: Preparation for moving CKEditor 5 to core, still using commit
8a8c4580417427d7644f66e218a0e7cc677f4cdd.Comment #24
daffie commentedTestbot is still not happy.
Comment #25
wim leersIndeed, not yet happy. Because I confused eslint compliance with ES6ification compliance.
Built using #3227826-28: Preparation for moving CKEditor 5 to core, still using commit
8a8c4580417427d7644f66e218a0e7cc677f4cdd.Comment #27
wim leersThis should fix most failures!
Built using #3227826-36: Preparation for moving CKEditor 5 to core, using commit
545040f7d1fe9eff138e2daa2dc1f5edb2aa8cab. Upstream commit history since the previous build:→ adding credit for @johnwebdev :)
Comment #28
wim leersThis should fix the remaining failures.
Built using #3227826-39: Preparation for moving CKEditor 5 to core (thanks @lauriii!), using commit
411c7358a3404d11ff1e2f0c1a638f43b37f072a. Upstream commit history since the previous build:Comment #29
wim leersThe 2.32 MB patch size might scare people away. ~75% of that is for the
core/assetsandcore/yarn.lockchanges. I think moving that part into a separate issue may be helpful — but I'll first await some initial reviews before doing that :)Comment #30
shaalFor those interested in taking CKeditor5 on Drupal 9.3.x for a spin,
I created a snapshot, using DrupalPod -
Username: admin
Password: admin
Click on the following link to open it -
When you see Gitpod's login screen, choose "Continue with Github".
https://gitpod.io#snapshot/ec39baf4-f241-40be-a7fe-e28163922a0e
Comment #31
larowlanIt would be good to verify that the new API will support modules like linkit and editor advanced link that have close to 200k installs between them.
Can we articulate a path forward for those modules - perhaps by creating an issue in their queue (if one doesn't exist) with guidance on how the update will look for them
I think without Ckeditor5 compatible versions of those modules, many will be blocked from updating, so this will be a barrier to adoption of D10.
Comment #32
wim leers#30: Thanks! :)
#31: On it.
#29: release manager @xjm indicated that it'd be better to hold off on that for now because it otherwise may need to be removed if the CKEditor 5 module is still alpha-level stability at the time when
9.3.0-rc1gets tagged. So, holding off on creating that separate issue.We will instead from now post multiple patches:
ckeditor5-CID.patch(includes everything)ckeditor5_assets_only-CID-do-not-commit.patch(assets only) andckeditor5_module_only-CID-do-not-commit.patch.Comment #33
wim leersComment #34
duaelfrHey! Great job here as usual! ;)
I created issues on both Editor Advanced Link and Editor File upload.
I might have some time during the DrupalCon Europe. We'll see ;)
Comment #36
wim leers#34: Wow, thanks for creating that! Added comment with relevant information from the CKEditor 5 team from the meeting earlier today: #3232052-2: Drupal 10 & CKEditor 5 readiness.
#31: See #34 and the above update for it, plus #3232190: CKEditor 5 readiness for LinkIt. In short: they're aware of this need, but so far they've managed to not have to support it. There are significant implications for focus state/accessibility, real-time collaboration conflict handling, et cetera. @lauriii and I discussed various potential approach with @Reinmar. He'll provide us with an update in ~2 weeks (September 23, 2021).
TL;DR: we're blocked on news from upstream to really make progress on this front. They understand how important this is to Drupal, and are prioritizing getting these aspects unblocked.
Related: we opened #3231341: Deprecate EditorLinkDialog, EditorImageDialog and EditorMediaDialog in Drupal 10.1 for removal in Drupal 11 a while ago for this.
Comment #37
webchick*cracks knuckles* Greetings! It's time for round 1 of WebChickTestCase! :D (This means I'm going in blind, without reading the rest of the issue, so I can experience things as a new user. Apologies if this repeats anything said already above.)
To test this, I used the GitPod link mentioned in #30. Firefox 91.0.2 (64-bit) on MacOS Catalina 10.15.7 (19H1323).
First thing I noticed is this CKEditor-specific toolbar added itself to my screen on any page with an editor on it. I'm assuming this is because there is a debug mode on or something in this patch? But would presumably need to be removed prior to commit.
Initially things worked great—Bold, Italic, Blockquote, Link (nice UX for that!), etc.—then I tried to add a media item. (Cue ominous music. :D) It seemed to upload and add a new image fine, but when trying to press the "Insert selected" button, nothing happens. :( I get some JS errors in the console...
And then after this, nothing seems to work... the toolbar is greyed out apart from the media button. :(
So... needs work, or I need to fix something on my end, but leaving at "needs review" so as not to spook off other potential reviewers.
Comment #38
xjmEdit: Disregard for now, missed a step...
Comment #39
xjmI was able to reproduce #37 using the contrib module's latest code. Steps I took:
en/admin/config/content/formats/add.en/node/add/article.This means that this is only a major bug (not a critical one) since there is a workaround of exiting out of the dialog and toggling away from the editor. Still stable-blocking for sure IMO since this the media integration is a key feature.
Comment #40
xjmPosted #3232409: Media Embed button is broken for #37.
Aside: Really should have done #3206522: Add FunctionalJavascript test coverage for media library. ;)
Comment #41
luke.leberI ran into something that was a bit confusing -- it may even be considered data loss? It seems that at least 'class' attributes are stripped from
h4,h5, andh6elements, but are seemingly persisted withh2andh3elements?Steps to reproduce:
Create a text format and ensure the following plugins are added to the toolbar:
Next...
h2element via the headings plugin.h2to anh3.h3to anh4.h4to anh3.See https://www.awesomescreenshot.com/video/5086163?key=09c1158229f0884b9d36... for a visual demo.
Overall, I'm liking the CKEditor5 UX. Keep up the good work :)
Comment #42
luke.leberI suppose that on the flip-side, there's also a discrepancy between the "Limit allowed HTML tags and correct faulty HTML" filter and what actually happens when content is saved.
The (read-only textarea) allowed HTML tags in the setup in #41 are:
<br> <p> <h2> <h3> <h4><h5><h6>, yeth2andh3seem to still allow the class attribute?Saving
seems to render the attributes to the front-end just fine when the content renders.
Comment #43
lauriiiI was able to reproduce the problem from #41 on a text format without HTML filter and I opened new issue for that #3233425: [upstream] h4, h5, and h6 fail to downcast GHS added attributes. However, I'm reading #42 so that the HTML filter was enabled when #41 was tested.
@Luke.Leber would you be able to export your text format and text editor configuration? That could be helpful for investigating this.
Comment #44
luke.leberre: #43 - I'll have availability tomorrow afternoon to export and provide the configuration. It seems like this might be a good candidate for a separate issue, so I'll open a new one in the ckeditor5 project's issue queue. The comments in #42 apply to both before and after enabling the filter. The attributes were happily rendered to the frontend in both scenarios, only raising my eyebrow when the filter was enabled.
It could very well be that the read-only text area that outlines the allowed elements/attributes isn't accurate. I honestly find it hard to believe that ckeditor would be rendering stuff to the frontend that wasn't explicitly downcasted (or is it upcasted? I mix the two up!).
Comment #45
luke.leberre: #44 - Here's where my source of confusion came from! The real problem here is that the "Limit allowed HTML tags and correct faulty HTML" read-only text area can appear in the filter settings UI without actually checking the box to enable the filter.
I think this issue might be a lot more trivial than originally thought, not being a filter problem at all, but just a confusing UX when setting up a new editor instance.
To reproduce:
In the steps above, the "Limit allowed HTML tags and correct faulty HTML" option under "Enabled filters" was never checked.
I would have expected to not see the filter settings appear until the filter was actually enabled.
Comment #46
droplet commentedI'm coming from #3233491: Create process for reviewing changes in 3rd party JavaScript dependencies
1. What reasons make it must build from DrupalCore? (eg. Assumed it helps a bit of the contrib development, is it must? and involved how many developers? less than 1%?)
2. Why not use this method: #3211214: Using a monorepo with workspaces for Standalone Core JS packages
3. If the above doesn't work, can we do this way: https://github.com/vuejs/vue/tree/dev/packages
Comment #47
yash.rode commentedI was able to reproduce the problem from #3231364-45: Add CKEditor 5 module to Drupal core on unnecessary filter settings and I opened new issue for that #3236648: The "Limit allowed HTML tags and correct faulty HTML" option under "Enabled filters" was never checked still shows the filter settings for it
Comment #48
lauriii#46.1 The current patch is simply built based on following pre-existing core policies. I guess as part of #3233491: Create process for reviewing changes in 3rd party JavaScript dependencies we could introduce changes to our policies that would make something like what you're proposing possible.
#46.2 We actually started with a structure where the JavaScript was decoupled from the Drupal module. It was very hard to maintain the JavaScript in a separate project because the JavaScript code in the libraries was heavily coupled with the Drupal module. Because the library was so heavily coupled with the Drupal module, it wasn't possible to test the libraries without the Drupal module. See #3216255: Move admin UI build process into module for #3215005: Move custom CKEditor 5 drupal plugins into module for context.
Comment #49
wim leers#37: the CKEditor-specific toolbar you mentioned: I think you installed the CKEditor 5 developer tools 🤓
#37–#40: Fixed in #3232409: Media Embed button is broken. (I agree with the aside in #40 ;))
#41–#43: @lauriii reproduced this and confirmed this is an upstream CKEditor 5 bug, for which he filed an issue too: https://github.com/ckeditor/ckeditor5/issues/10539 👍 The CKEditor 5 team is really grateful for our bug reports 😊
#44 + #45 + #47: Fixed in #3236648: The "Limit allowed HTML tags and correct faulty HTML" option under "Enabled filters" was never checked still shows the filter settings for it.
#46: to add to what @lauriii already wrote in #48: we can absolutely change this in the future. But there already are some huge hurdles that we have to overcome here. 😅 Innovating on Drupal's JS package handling isn't one that we should put in the critical path. 🙏
Built using #3227826-42: Preparation for moving CKEditor 5 to core using commit
686cce684c3edc7874db11ece8149a8bcf702b3a. Upstream commit history since the previous build:New since last time: #3227890: Add ckeditor5-special-characters to allow inserting special characters for users that do not know the native picker + #3227875: Add ckeditor5-remove-format to allow removing formatting from pasted content. These bring us closer to complete feature parity. Only a few issues remain. Which reminds me: we have not yet moved the roadmap issue into Drupal core. Did that just now: #3238333: Roadmap to CKEditor 5 stable in Drupal 9.
Comment #50
catchThis is tagged with release manager review, I'm happy to review anything that has specific release management questions, but overall I think the pressing thing is to get this committable and into 9.3.x, so that we can deprecate ckeditor 4 and remove it from Drupal 10. The biggest concern I have is how robust the upgrade path will be on real sites - but again a core experimental module is the way to flush out problems there.
#3233491: Create process for reviewing changes in 3rd party JavaScript dependencies we need to figure out a plan for, but it's not a new issue introduced by this patch, and any theoretical issues resulting from it are less likely than an unpatched ckeditor4 vulnerability once it's out of support, so it shouldn't be a blocker here.
Comment #51
wim leers💯
This is why I focused my time on that very question since I started working on this in earnest ~3 months ago! 😊
It's why we use config validation constraints to help guarantee correct configuration, and why we have the concept of "smart default settings" (see
\Drupal\ckeditor5\SmartDefaultSettings).It's why we (in particular @bnjmnm!) spent a lot of time on making the UX of using the UI to switch from CKEditor 4 to CKEditor 5 over at
/admin/config/content/formats/manage/*solid and informative, so that people testing it now (before the upgrade to Drupal 10) are informed in detail of the what and why. We can choose how (or even if) to expose those messages to the end user when it happens automatically when upgrading from 9 to 10.It's why we have
\Drupal\Tests\ckeditor5\Kernel\SmartDefaultSettingsTestin particular: it provides 6 different testing scenarios (3 that cover Drupal 8's default text formats without changes:basic_html+restricted_html+full_html, plus two with high-impact changes tobasic_htmland finally one that tests a text format that uses onlyfilter_htmlwith its default settings). If I were you, I'd focus my attention (or at least start with) scrutinizing that test. If you have a suspicion that edge cases X or Y are not handled, it's going to be trivial for us to expand test coverage there.For upgrade path robustness, what remains to be done there is:
\Drupal\ckeditor5\SmartDefaultSettings::mapCKEditor4ToolbarButtonToCKEditor5ToolbarItem()+\Drupal\ckeditor5\SmartDefaultSettings::createSettingsFromCKEditor4()). We of course want contrib modules (which provide additional CKEditor 4 plugins, buttons and settings) to be able to specify an upgrade path as well.Comment #52
wim leers@catch: Clearly #50 is from the POV, what would you write from the POV? 🤓
Comment #53
catch@Wim Leers: nothing from a framework manager point of view yet, because I haven't reviewed yet.
Once #3226335: Follow-up for #3216015: allow contrib & custom Drupal modules providing CKEditor 4 plugins to specify their CKEditor 5 equivalents + settings to be migrated is fixed, what happens when a site tries to update, but a plugin it uses hasn't implemented an upgrade path?
Comment #54
wim leersAny buttons for which no upgrade path is defined will be dropped.
Any plugin settings for which no upgrade path is defined will be dropped.
Most importantly: 100% of the stored HTML will still be editable after the migration, thanks to the Source Editing plugin getting enabled when needed.
Comment #55
catchWhat happens if the plugin later adds an upgrade path and you enable it, will the old markup get upgraded on the fly, or is it stuck in edit source?
Comment #56
wim leersNot sure I follow. So I'll just explain the different aspects:
In fact, when it becomes available, they'll be notified explicitly: they'll get the
SourceEditingRedundantTagsConstraint::$availablePluginsMessagevalidation error which says:The following tag(s) are already supported by available plugins and should not be added to the Source Editing "Manually editable HTML tags" field. Instead, enable the following plugins to support these tags: %overlapping_tags..If they then actually add this newly available toolbar item, they'll get the
SourceEditingRedundantTagsConstraint::$enabledPluginsMessagevalidation error which says:The following tag(s) are already supported by enabled plugins and should not be added to the Source Editing "Manually editable HTML tags" field: %overlapping_tags..(Both scenarios have test coverage in
ValidatorsTest— see theINVALID Source Editable tag already provided by plugin and another available in a not enabled plugintest case.)Let's apply this to a concrete example: imagine there's a
marqueebutton to add<marquee>markup in Drupal 9, and you've gotfilter_htmlconfigured to only allow<p> <br> <strong> <marquee>. No upgrade path is defined for it at the time the site upgrades from Drupal 9 to 10. This means that aEditorconfig entity with these settings will be generated during the upgrade:(
<p> <br>are supported by CKEditor 5 core — you cannot disable them.<strong>is supported bybold.<marquee>is supported by nothing, which is why we're explicitly adding it to the list of that thesourceEditingplugin allows you to configure. If you put all of that together, you can see that CKEditor 5 can generate and edit exactly the set of HTML tags that the text format's HTML restrictions allow 👍)Then, once a
marqueebutton becomes available that supports that tag, you'd first get that first message when interacting with your text format/editor in the UI. To fix it, you'd add themarqueebutton:(This is the state immediately after dragging that toolbar item into the "active toolbar" in the UI.) You still won't be able to save it though. You'll get that second message now! You'll have to manually remove that tag, which means you're now in this state:
Now you will be able to save the text editor. You can choose to remove the
sourceEditingbutton, or you can keep it to edit your other markup — there are just no additional allowed tags specified.In other words: the module does nudge you towards doing the right thing: it nudges you towards using plugins instead of — because the user experience is way worse there.
Comment #57
wim leers@lauriii and I met with @Reinmar from the CKEditor 5 team yesterday. Meeting notes available.
Outcomes:
editor_advanced_linkandlinkitportability were our top concerns. The challenge here is that we'd love for those two modules to not need a clunky Drupal form/dialog anymore. It's clunky (form-based UI instead of the elegant and less in-your-face balloon UI of CKE5 and slow (requires a round trip to the server). But … that's the ideal. If need be, there's no reason we can't fall back to that for those scenarios.So here are the next steps:
EditorLinkDialoginstead of CKE5’s link.EditorLinkDialogwhen that signal is present. Pointers:https://github.com/ckeditor/ckeditor5/blob/ab03609f2c599ed4aa9ee758d1e14...
+ https://github.com/ckeditor/ckeditor5/blob/ab03609f2c599ed4aa9ee758d1e14...
(BTW, I provided a patch for what is implementable today: #3232052-5: Drupal 10 & CKEditor 5 readiness. But the above is necessary to port 100% of their functionality.)
<ol start>support! 🥳StylesComboplugin will start after this! 🥳Comment #58
wim leersAaand … everything I wrote in #51 wrt upgrade path has been completed in https://www.drupal.org/project/ckeditor5! :)
Built using #3227826-44: Preparation for moving CKEditor 5 to core using commit
bf5df30c36153131e56b2ca11c1148007645aa92against9da1866da41f0bfcdb90e1f8901ce8919549f189in9.3.x. Upstream commit history since the previous build:New and notable since last time: upgrade path (as mentioned before), #3227871: Add ckeditor5-paste-from-office to allow pasting from Microsoft Office & Google Docs (again closer to complete feature parity!),
ckeditor5.api.php, improved DX.Comment #59
tim.plunkettAdd missing tag
Comment #60
wim leersIt's been very quiet here. But we've not been idle.
We've been pushing forward the CKEditor 5 module itself, fixing more edge cases, adding more tests, and so on. Mid next-week, there will be a new CKEditor 5 release. Once that's out, we'll be able to address a few things we've been unable to address.
But at least equally crucially, we've been pushing forward the two most popular CKEditor 4-integrating contrib modules: https://www.drupal.org/project/linkit and https://www.drupal.org/project/editor_advanced_link.
Editor Advanced Link
We've been working with the CKEditor 5 team to figure out a way to bring the Editor Advanced Link experience to CKEditor 5 without having to sacrifice the superior CKEditor 5 linking experience (which does not rely on a Drupal-rendered dialog, which is very prone to network latency).
@lauriii collaborated with https://github.com/oleq to get that to work:

And then I worked on the automatic upgrade path, which was just completed:

Linkit
Here too we've been working with the CKEditor 5 team! Again @lauriii has been collaborating with https://github.com/oleq, and again with great results:This is using https://www.drupal.org/project/a11y_autocomplete (which will soon replace jQuery UI Autocomplete in Drupal core — see #3076171: Provide a new library to replace jQuery UI autocomplete). That's right; we're reusing Drupal JS components in our CKEditor 5 integration, and it required zero hacks. 🤩 However, the Linkit module's use of jQuery UI autocomplete was actually pretty advanced … so advanced that it was doing things https://www.drupal.org/project/a11y_autocomplete could not yet do. That's why @lauriii, @bnjmnm and @nod_ have been collaborating for the past few weeks on this, and it's actually been a great way to validate the work in
a11y_autocomplete: this is a prominent, high-profile use case, and they've been expanding API support in several ways to enable the LinkIt use case!In particular, Linkit needs grouping and richer results, which you can see in this screenshot from its project page:

Cheer them on in #3245114: Allow grouping search results, #3243749: normalizeSuggestionItems() handles additional properties inconsistently and other issues in that project. This is an unexpectedly nice coincidence where we're validating one thing by working on another! 🥳
Comment #61
larowlanAwesome news and work folks!
Comment #62
ambient.impactI'll also add awesome work! 🎉
Comment #63
tim.plunkett@webchick and I spent time going through this together, and identified 4 concerns (2 of which already had issues open!)
First there was a question about "what are CKE plugins?" and "do I need to know?" prompted by the messages upon switching an existing editor:
#3245967: Messages upon switching to CKEditor 5 are overwhelming
There was some wonkiness with the Image Upload checkbox that is being fixed here (already RTBC):
#3245320: Automatic upgrade path always disables image uploads — in the UI
Hit some issues with editing the markup in Source mode that is covered here:
#3229174: Making changes directly in the source view drops the made changes on save
This was fixed in upstream, and the new release came out today so that will be fixed in this MR shortly.
In our testing of pasting in a tweet (with accompanying <script> tag), we hit this bug:
https://github.com/ckeditor/ckeditor5/issues/9659
Which could be addressed by usage of the "HTML Embed" plugin:
#3245950: [upstream] <script> tag support in GHS
Comment #64
webchickYep, as Tim mentioned we kicked the tires on this pretty hard yesterday, for over an hour. I'm especially impressed with how nice the new version looks/feels, and the a11y of the toolbar config UI. :)
Most of my review centered on:
It is quite common for people to use "Full HTML" to do things like copy/pasting an ad code into a sidebar block, or putting Twitter embeds in the middle of an article, or what have you. Under the current behaviour:
<script>are completely stripped from the content, and after saving, the original markup is irretrievable. This leads to data loss. :(Tim and I went back and forth about what to do about this... warn people before they save something with disallowed tags, and direct them to add (or more likely get an admin to add) the tags to the HTML filter? (Definitely not ideal; we don't have an existing interaction pattern for this, and in 99% of cases the content author getting the error can do nothing about it.) Make "Full HTML" truly "Full HTML" and add literally ALL of the possible tags/attributes to any format with the "Skip HTML processing" (or whatever that option's called) bit on so it strips nothing? Or if not doing that, at least allowing
<script>tags in those cases? (Definitely not ideal from a security/design standpoint; if anything, we want fewer tags people can shoot themselves in the foot with.) Etc.I said that my Product Manager sign-off for Beta was conditional on figuring out a path forward for that problem. #3245950: [upstream] <script> tag support in GHS sounds like a very solid approach to me, that also potentially addresses a usability problem in addition to solving the data loss problem, while retaining security. I would make that a Stable blocker, but would rather get this out in front of people with that documented as a known issue than block this feature for an entire release on figuring it out.
Product Management sign-off: complete. :)
Comment #65
larowlanFwiw most of our clients would be ok with the stripping of invalid html, it's not that different to what CKEditor 4 is doing when we've configured allowed tags. In most enterprise settings there is no full HTML and stripping non allowed html attributes and tags is a required feature. So I think it's a good idea to get this in front of people with that known issue listed.
Comment #66
catchAnother option if you have a limited set of content with full HTML and complex markup you don't want stripped is to disable ckeditor on that text format entirely (if it's not already). Agreed this shouldn't be a blocker to inclusion as an experimental module at all.
Comment #67
wim leersSince #60, we now also have a fully operational
linkitmodule with CKEditor 5: both UX and upgrade path. See #3232190-12: CKEditor 5 readiness and later. It looks like this:Built using #3227826-50: Preparation for moving CKEditor 5 to core using commit
8031f5b7198cfc6b7ca30b4451934b48bb890e32against9da1866da41f0bfcdb90e1f8901ce8919549f189in9.3.x. Upstream commit history since the previous build:New and notable since last time: hardened upgrade path (and also now proven further thanks to working upgrade paths for
linkitandeditor_advanced_link), functional JS test coverage for media/media library (#3206522: Add FunctionalJavascript test coverage for media library), improved DX, and we're on CKEditor 5 https://github.com/ckeditor/ckeditor5/releases/tag/v31.0.0 now 😊Thanks, @effulgentsia for filing a whole bunch of issues in https://www.drupal.org/project/ckeditor5, we've addressed some but not yet all.
Comment #68
wim leers#3226052: Update to cspell 5 was committed while I was creating #67 🥸
Built using #3227826-51: Preparation for moving CKEditor 5 to core using commit
8031f5b7198cfc6b7ca30b4451934b48bb890e32against3eba4b3c583e94b3e2306ca0c141251e0939d7b1in9.3.x. No upstream commits.Comment #69
wim leers#68 applied cleanly, but failed on cspell (not surprising since it just was changed), but also on a bunch of
phpcsviolations, which is surprising, because https://www.drupal.org/project/ckeditor5 is explicitly using core'scommit-code-check.sh🤔Also, #2909370: Fix 'Drupal.Commenting.VariableComment.IncorrectVarType' coding standard just landed, which causes newphpcsviolations.I cannot reproduce those failures: #3233107-3: [ignore, testing issue] Fake bug report 😬 So instead I worked on a PoC fix, tested it in a helper issue, and am now confident it will be green here too.
Built using #3227826-51: Preparation for moving CKEditor 5 to core using commit
a587204ef3678612991237bf5a5dc8b5e6cf7a6cagainst3eba4b3c583e94b3e2306ca0c141251e0939d7b1in9.3.x. Upstream commit history since the previous build:Comment #70
larowlanWow! That is amazing and will be a huge win for D10 uptake - thank you!
Comment #71
wim leersHighlights since #69:
jsdom. We'll need to do a library evaluation for that. That issue was a blocker to a long-known data loss issue: #3222808: Follow-up for #3201646: markup in image captions is lost.backend framework manager, we've been working to address those as well.core/package.json— all for the better! 😊<ol start>support, are discussing the CKE5 successor to CKE4'sStylesCombo, and are looking into providing official CKE 4 → 5 plugin mapping recommendation docs (essential for getting Drupal contrib modules ported) 👍I believe the following issues should still block commit, and 2/3 are very close; all should land early next week:
Built using #3227826-58: Preparation for moving CKEditor 5 to core using commit
07dbfdc24c0cf332c40a7d379d5d7f816324e723against707121c9cc46266be7d922b5ff096f07cb9461eein9.3.x. Upstream commit history since the previous build:Comment #72
wim leersAfter hours of prep work to make sure the core patch is green on the first attempt I of course forget the interdiff 😅
Comment #73
wim leersSince #71, #3246524: Make more (all?) classes @internal and #3246280: Defense in depth: add anti-CSRF token to this module's routes have landed.
#3246169: Embedded media are not linkable through UI; already linked embedded media are unlinked (data loss!) is 95% ready, will be finished tomorrow.
Built using #3227826-65: Preparation for moving CKEditor 5 to core using commit
3ca84023f364eb773b723fa075f9be30f79e837fagainstd63941bc1af2e1a31debad1f202e46351eaa149din9.3.x. Upstream commit history since the previous build:Comment #74
effulgentsia commentedI did the (backend) framework manager review on this. The critical issues that I filed are fixed and in #73, so removing the "needs framework manager review" tag. I filed some normal priority issues that haven't yet been fixed, but I'm fine with them happening post beta.
I did not review the frontend code, but this issue still has the "needs frontend framework manager review" tag for that.
Comment #75
lauriiiI've updated the roadmap with issues I've discovered while reviewing the code. I have to acknowledge that I'm not fully impartial to review this since I've done a lot of work on the JavaScript aspects of the module. That said, I still feel comfortable removing the tag given that all of the work has been peer reviewed, the frontend APIs provided by the module are very minimal (almost all of the frontend code is marked as internal), and there will be still some time for additional reviews until the module is marked as stable.
These issues should be addressed before the module is ready to be marked as beta:
core/assets/vendordirectory which I don't necessarily agree with. Image and media plugins are heavily coupled with the modules, and cannot be outside of that context. For consistency, I think the other plugins should be there too.@ckeditor/ckeditor5-dev-utilsis listed twice in the package.jsonjsdomlibrary which was added in #71Comment #76
wim leers#3246169: Embedded media are not linkable through UI; already linked embedded media are unlinked (data loss!) landed this morning.
#75.2 and .3 are already fixed. I'll need help to address #75.1 — but I 100% agree with that!
Built using #3227826-67: Preparation for moving CKEditor 5 to core using commit
7e3cf3bacce08f39c3c69b1081cefc2a9a15cf8bagainstd63941bc1af2e1a31debad1f202e46351eaa149din9.3.x. Upstream commit history since the previous build:Comment #77
wim leersBuilt using #3227826-67: Preparation for moving CKEditor 5 to core using commit
48d0ae0dc22ff864e2c5b057d9be5646254460d0againstd63941bc1af2e1a31debad1f202e46351eaa149din9.3.x. Upstream commit history since the previous build:I once more really wish
core/scripts/dev/code-commit-check.shwere available for contrib projects 🥲No idea why our monkeypatched variant of it did not catch this 🤷♂️Comment #78
effulgentsia commentedMultiple committers have already commented on this issue, most recently #74 and #75, so removing the "needs committer feedback" tag.
Comment #79
wim leersGreen! Now just to address #75.1 (requires new patch) and .4 (requires addition to issue summary).
FYI: a few hours before #75, I updated #3238333 thoroughly for everything that happened in the past ~40 days, see #3238333-7: Roadmap to CKEditor 5 stable in Drupal 9. @lauriii as part of #75 added all additional issues he identified as FEFM: #3238333-8: Roadmap to CKEditor 5 stable in Drupal 9.
Comment #80
tim.plunkett#3248522: Move custom CKE5 plugins outside of core/assets/vendor is one issue that should ideally land first, but I do not think it blocks commit.
After discussion with the team and my own review of the module, I am marking this RTBC.
Thanks to everyone who worked on this!
Comment #81
bnjmnmAdded jsdom dependency evaluation to issue summary
Comment #84
lauriiiCrediting folks who have contributed to the development of the patch.
Comment #85
wim leersAnd now #3248522: Move custom CKE5 plugins outside of core/assets/vendor is done! 🥳
Built using #3227826-73: Preparation for moving CKEditor 5 to core using commit
fbacec8247208f39472d3d8544c540676404dfe5againstbd80b71a6f0539a792b1f925b59d607564706fd1in9.3.x. Upstream commit history since the previous build:P.S.: we promise the interdiff is only scary because we moved things around 😇
Comment #86
lauriiiThis should fix the commit-code-check.sh 😇
Comment #87
bnjmnmThis fixes the Nightwatch failure that appeared in the post credits stinger.
Comment #88
tim.plunkettGreat, thanks! As I mentioned when I RTBC'd, that was important to land but not a commit blocker. But happy to have ironed out all the resulting changes now rather than later.
Consider this re-RTBC'd
Comment #89
catchDiscussed this quickly with @xjm since it's still tagged for release manager review. I haven't managed to do a full code review here, although I'm confident that plenty of other people have.
I think there were two remaining concerns (now that a lot of (all known?) data loss issues are fixed):
1. Docs for contributed modules porting - this is somewhat blocked on upstream, so we should move it to a stable blocker instead of a beta blocker (it's also mostly going to live on Drupal.org, so not directly part of this patch anyway).
2. Some kind of plan for dealing with third party production js dependencies (updates, reviewing updates etc.), but that's also not blocking and not specifically a ckeditor issues (although it makes it more pressing).
Overall I think it's much more important to have this in core in 9.3.x so that it gets run through its paces earlier than later.
Comment #90
effulgentsia commentedThis is failing some pre-commit checks. I'll come back to it later today to see if it's just on my machine or if it's a real issue with the patch.
Comment #91
larowlanCan we get a change record for this amazing piece of work? Thanks
The pre-commit checks passed for me, FWIW
Comment #92
larowlanComment #95
effulgentsia commentedPhenomenal work on this, everyone! Pushed to 9.4.x and cherry picked to 9.3.x.
Needs work for the change record, but I didn't want that holding up getting this into the beta.
Comment #96
larowlanComment #97
gábor hojtsyComment #98
wim leers@lauriii just published a change record (basically matching the https://www.drupal.org/project/ckeditor5 project page, which was indeed written as a change record for an experimental module): https://www.drupal.org/node/3249061.
We will expand that change record with guidance on how to port modules providing CKEditor 4 plugins (most can be found at https://www.drupal.org/project/ckeditor/ecosystem and https://www.drupal.org/node/2735151).
That is impossible to provide right now because:
npm.Comment #99
wim leersCan we get a
ckeditor5.modulecomponent in the project, so we can move over all open issues from https://www.drupal.org/project/issues/ckeditor5?categories=All into it? 🙏😊(Or would we prefer to move 100% of issues over? 🤔 I do not have a strong opinion. I think it's probably best to move only over the remaining open ones; the rest predate the commit history in Drupal core anyway.)
Comment #100
lauriiiCreated the
ckeditor5.modulecomponent 👍 I think we should move all issues from the issue queue to the core queue under the new component.Comment #101
wim leers… starting with this one then 😊
Comment #102
xjmComment #103
xjmComment #105
xjmRemoving the intermediate parent issue.
Comment #106
nod_issue broke the yarn vendor-update command #3258371: fix yarn vendor-update command
Comment #108
rgpublicI sincerely hope, "No Drupal dialogs in CKEditor anymore" doesn't mean support for it will be removed completely...? After all Drupal.ckeditor5.openDialog() in core/modules/ckeditor5/js/ckeditor5.js exists and for some use-cases it's in fact very nice to have this option still available. Not everything can be crammed into a tiny bubble and sometimes you need really need Drupal's backend features, form validation, form fields etc. I have nothing against the link feature in a bubble, though. Just wanted to argue for keeping the dialog feature alive.