Provide opt-out for v46+ opinionated typography defaults in .ck-content
📝 Provide a description of the new feature
CKEditor 5 v46+ introduced opinionated typography defaults that are explicitly applied via the .ck-content selector:
.ck-content {
font-family: var(--ck-content-font-family);
font-size: var(--ck-content-font-size);
color: var(--ck-content-font-color);
line-height: var(--ck-content-line-height);
}
These defaults create significant integration issues in CMS environments like Drupal where:
- Content needs to inherit typography from custom themes and modules
- We don't control our clients' CSS customizations
- Thousands of existing sites expect CKEditor content to respect site-wide typography
This is especially noticeable in our DXPR Builder module which uses the CK5 inline editor on frontend pages for WYSIWYG editing. It is important here that we don't override the user's custom theme and branding. It is also impossible for us to "fix" it in our product by setting the variables because we would not know what font-family our clients use on any given site.
I suspect it will also prove to be a problem in Drupal core: https://www.drupal.org/project/drupal/issues/3538768#comment-16359381
The problem: The .ck-content selector creates a new inheritance context that overrides site typography. Simply overriding the CSS variables with inherit, unset, or reset doesn't work because:
- The properties themselves in
.ck-contentcreate the override - The specificity and cascade rules mean these properties take precedence over theme styles
- Child elements inherit from
.ck-content, not from the original document flow
This breaks typography inheritance in ways that can't be fixed without removing the properties from .ck-content itself.
Our current workaround
We've had to implement a complex build-time workaround that processes CKEditor source files. The opinionated styles appear in two separate places requiring different handling:
1. Backend (Editor UI): Modify core theme files before webpack bundling
const removeTypography = (css) => {
['font-family', 'font-size', 'color', 'line-height'].forEach(prop => {
css = css.replace(
new RegExp(`(\\.ck-content[\\s{][^}]*?)\\s*${prop}:\\s*var\\(--ck-content-${prop === 'color' ? 'font-color' : prop}\\);?`, 'g'),
'$1'
);
});
return css;
};
// Process source files before our webpack build
['node_modules/@ckeditor/ckeditor5-core/theme/core.css',
'node_modules/ckeditor5/node_modules/@ckeditor/ckeditor5-core/theme/core.css'
].forEach(file => {
if (fs.existsSync(file)) {
fs.writeFileSync(file, removeTypography(fs.readFileSync(file, 'utf8')));
}
});
2. Frontend (Content Styles): Process the pre-built ckeditor5-content.css distributed in your npm package
// Extract from node_modules/*/ckeditor5/dist/ckeditor5-content.css
// This is a pre-compiled file from CKEditor, not generated by our build
let css = fs.readFileSync('node_modules/ckeditor5/dist/ckeditor5-content.css', 'utf8');
// Neutralize CSS variables and remove typography properties
['font-family', 'font-size', 'font-color', 'line-height'].forEach(prop => {
css = css.replace(new RegExp('--ck-content-' + prop + ':[^;]+;', 'g'), '--ck-content-' + prop + ':inherit;');
});
css = removeTypography(css);
This fragile workaround:
- Requires maintenance with every CKEditor update
- Manipulates node_modules post-install
- Processes files in two separate locations
- Adds complexity to our build pipeline
- Could break with internal CKEditor structure changes
Proposed solution
Provide a configuration option to opt out of opinionated styles, for example:
ClassicEditor.create(element, {
opinionatedStyles: false
})
Use case
Content Management Systems and site builders where:
- Typography is controlled by themes/design systems outside CKEditor
- Content must seamlessly inherit site-wide typography
- The editor is one of many content creation tools
- Consistent typography across all content sources is critical
Related discussion: https://github.com/ckeditor/ckeditor5/issues/18710
If you'd like to see this feature implemented, add a 👍 reaction to this post.
Thanks a lot for the detailed report and for outlining your current workaround, we really appreciate the level of context you’ve provided here.
Regarding the typography reset: we’ve been evaluating whether mechanisms like @layer or additional stylesheets. Layers are definitely interesting from a CSS-architecture perspective, but they also introduce their own challenges, especially once you factor in environments that export inline styles, email pipelines, legacy CSS tooling, or CMS pipelines that can’t control stylesheet ordering. Additional stylesheets are quite cumbersome for new users, every new integration layer, even as small as a stylesheet, becomes broken installations and support tickets. Editor loading stylesheets or styles: we've been there in the old installation methods, and decided to drop this magical approach.
Because of this, any approach that involves additional stylesheets or layer-based cascade management may become quite problematic. That said, the topic would require research on our side.
One idea that might be worth exploring from the integrator side is whether systems with complex theming requirements (like Drupal, DXPR, etc.) could opt out of our content styles entirely and ship their own minimal content stylesheet tailored to their theme. In some scenarios this may actually provide the cleanest “inherit everything” experience without needing CKEditor to dynamically disable parts of its default styling. It’s not a trivial path, but for highly customized environments it might offer the most predictable long-term result.
I will bring up this topic internally, also @Reinmar @oleq @filipsobol you can take a look.
One idea that might be worth exploring from the integrator side is whether systems with complex theming requirements (like Drupal, DXPR, etc.) could opt out of our content styles entirely and ship their own minimal content stylesheet tailored to their theme
I think this is the only realistic scenario.
What we perhaps could improve on our end, is organizing content styles in two groups:
- Essential, without which features will not work at all
- Additional, that improves the overall experience (more opinionated)
We tried to avoid the second group over the years, but that has been backfiring at us all the time. By default, the editor just did not work well.
Also, the separation between these essential content styles and opinionated ones isn't always clear. And there are dependencies between them. That's why I think it may not be possible to completely split them. Rather than that, it may happen that the best option is to better organize them within one file.
Right now, content stylesheet is automatically generated out of dozens of files. But with the new installation methods this is perhaps now more controllable for us and we could have them centralized. With that, we could document and improve readability of these styles.
In best case scenario, I'd physically split them into two essential and additional styles, e.g. by using two separate classes:
-
.ck-content-essential(or.ck-contentfor semi-backward compat) -
.ck-content-opinionated(or typography/or something)
And as @jjroelofs mentioned, config.useOpionantedStyles could control whether the second class is added to the editor. And when displaying content on external websites, integrators would just pick one or two classes, as they want.