CKEditor5 scoped styles with PostCSS
The Drupal 10 update is moving to CKEditor 5. What’s different? It’s no longer an iframe! So how do we scope any custom styles we want to include?
by
rikki.bochow
/ 23 May 2023
First and foremost, if you haven’t read the Drupal docs about including custom styles, then please read that. It will give you the necessary context.
This article is specifically about a theme setup that already uses PostCSS (as opposed to Sass - this is much easier with Sass), has various component stylesheets, and includes some level of theme CSS to the CKEditor window to help improve the content editor experience.
Simply including the same styles used in CKEditor 4 to CKEditor 5 now bleed out into the admin theme, so we need to scope them to the .ck-content
class.
Let's just say the theme's original ckeditor.css
file looks something like this:
@import "./custom-properties.css";@import "./base/base.css";@import "./button/button.css";@import "./layout/layout.css";body { font-family: var(--font-family); padding: .5rem;}
We use a couple of PostCSS plugins already, notably postcss-import
and postcss-preset-env
but in order to wrap everything here in a certain class, including everything we’re importing…
We need a new plugin
I tested a few class prefixing plugins, but the only one that suited my requirements was postcss-prefixwrap. With it installed, here’s our basic postcss.config.js
:
module.exports = { plugins: [ require("postcss-import"), ... other plugins require("postcss-prefixwrap")(".ck-content", { whitelist: ["docroot/themes/my_theme/src/ckeditor.css"], nested: "&", ignoredSelectors: [":root", /^\\.ck-(.+)$/], }), ],}
We place it last; we add the class to use as the prefix .ck-content
and specify our options;
- whitelist: our
ckeditor.css
, so this plugin only applies to that file. - nested: because we use ampersand for nested selectors
- ignoredSelectors: include the
:root
where we have some global custom properties and any class that starts with.ck-
because it’s already scoped.
The only change we need to make to our ckeditor.css
file is to change our body
styles to live on .ck-content
instead. Otherwise, they’ll come out at .ck-content body
and be ignored.
Now every selector in our generated ckeditor.css
file (that we didn’t ignore) is prefixed with .ck-content
; thus all the styles are scoped to CKEditor 5 and no longer bleed into the admin theme.
A note on CSS Custom Properties
If you (like me) prefer to preserve your custom properties, you may find the need to scope them as well, to avoid clashes with custom properties the admin theme might have.
For this, I added one more PostCSS plugin postcss-variables-prefixer;
module.exports = { plugins: [ require("postcss-import"), ... other plugins require("postcss-variables-prefixer")({ prefix: "pnx-", }), require("postcss-prefixwrap")(".ck-content", { whitelist: ["docroot/themes/my_theme/src/ckeditor.css"], nested: "&", ignoredSelectors: [":root", /^\\.ck-(.+)$/], }), ],}
This isn’t specific to the ckeditor.css
file, but that’s ok with me; they can be unique everywhere.
Hopefully, this helps make the transition to CKEditor 5 a little smoother for your content editors when updating to Drupal 10.