Integrates CKEditor 5 into your Strapi project as a fully customizable custom field. (Community edition)
- Extensive configuration
- Media Library integration
- Dark theme support
- Fullscreen expansion
- Responsive images support
- Automatic UI translations
- i18n support
- Self-Hosted
Strapi v5:
Add the package to your Strapi application:
yarn add @_sh/strapi-plugin-ckeditor
Then, build the app:
yarn build
Strapi v4:
Version 3 of the plugin will remain available for Strapi v4 until March 2026. Refer to the v3 installation guide for setup instructions.
Note: Version 3 receives only essential bug fixes. The configuration process and available features in version 3 differ significantly from the latest plugin versions.
The field can be fould in the Content-Type Builder under the CUSTOM
tab:
Presets
A preset is a set of settings that define the editor's features and appearence. You can specify a dedicated preset for each field. The available presets can be customized through the configuration.
The plugin provides two presets out of the box: Default HTML editor
and Default Markdown editor
,
each has different output format: HTML and Markdown, respectively. Both presets include
an extensive set of non-premium CKEditor plugins.
Responsive images
The plugin generates srcset
attribute for inserted images if the image has any formats
other than thumbnail
.
UI language: If you don't specify the UI language in the editor configuration, the plugin will default to the Strapi admin's preferred language. If no preference is set, English will be used as a fallback.
Content language: i18n for the editor's content language can be enabled by checking the
Enable localization for this field
option in the Advanced Settings tab.
The plugin configuration must be defined on the front-end. The plugin provides a setPluginConfig
function, which accepts a plugin configuration (PluginConfig
) that can include an array of presets
and a theme object:
import { setPluginConfig } from '@_sh/strapi-plugin-ckeditor';
function setPluginConfig(pluginConfig: {
presets: Preset[] | undefined;
theme: Theme | undefined;
}): void;
Key points:
- The function must be invoked before the admin panel's bootstrap lifecycle function. The general recommendation is to call it inside the admin panel's register lifecycle function.
- Provided properties will overwrite the default configuration values.
- The configuration becomes immutable after the first invocation, preventing further modifications.
Plugin configuration object includes optional presets
and theme
properties:
type PluginConfig = {
/**
* Presets are sets of settings that define the editor's features and appearance.
*/
presets?: Preset[];
/**
* Styles applied globally to every editor instance.
*/
theme?: Theme;
};
presets
is an array of objects of type Preset
. Each preset includes the following properties:
type Preset = {
/**
* Preset name, displayed in the schema.
*/
name: string;
/**
* Preset description, displayed in the Content-Type Builder.
*/
description: string;
/**
* CKEditor configuration object.
*
* @see {@link https://ckeditor.com/docs/ckeditor5/latest/getting-started/setup/configuration.html | CKEditor documentation}
*/
editorConfig: EditorConfig;
/**
* Additional styles applied to the editor instance after the theme styles.
*/
styles?: EditorStyles;
};
theme
object defines a plugin CSS styles applied to every editor instance. It includes the
following properties:
/**
* The `common` styles are applied first, followed by `light` or `dark` styles
* according to the preferences, and finally `additional` styles.
*/
type Theme = {
/**
* Core styles.
*/
common?: EditorStyles;
/**
* Styles apllied in light mode.
*/
light?: EditorStyles;
/**
* Styles apllied in dark mode.
*/
dark?: EditorStyles;
/**
* Additional styles that complement the theme.
*/
additional?: EditorStyles;
};
/**
* Represents styles that can be applied to an editor instance.
* Can be a plain CSS string or an array of interpolations for dynamic styling.
*/
export type EditorStyles = string | Interpolation<object>[];
Default presets and theme
To simplify the process of defining a new preset, the plugin exports default presets and a default theme, which can be used as a base in custom configurations:
import {
defaultTheme,
defaultHtmlPreset,
defaultMarkdownPreset,
} from '@_sh/strapi-plugin-ckeditor';
Integration with Strapi's Media Library
To integrate CKEditor with the Strapi's Media Library, the plugin provides two CKEditor plugins that can be included in your presets without additional configuration:
import { StrapiMediaLib, StrapiUploadAdapter } from '@_sh/strapi-plugin-ckeditor';
Available type definitions
The following type definitions are available for use:
import type {
PluginConfig,
Preset,
EditorConfig,
Theme,
EditorStyles,
} from '@_sh/strapi-plugin-ckeditor';
Type definitions
/**
* Plugin configuration object.
*/
export type PluginConfig = {
/**
* Presets are sets of settings that define the editor's features and appearance.
*/
presets?: Preset[];
/**
* Styles applied globally to every editor instance.
*/
theme?: Theme;
};
/**
* Preset is a set of settings that define the editor's features and appearance.
*/
export type Preset = {
/**
* Preset name, displayed in the schema.
*/
name: string;
/**
* Preset description, displayed in the Content-Type Builder.
*/
description: string;
/**
* Additional styles applied to the editor instance after the theme styles.
*/
styles?: EditorStyles;
/**
* CKEditor configuration object.
*
* @see {@link https://ckeditor.com/docs/ckeditor5/latest/getting-started/setup/configuration.html | CKEditor documentation}
*/
editorConfig: EditorConfig;
};
/**
* CKEditor configuration object.
*
* @see {@link https://ckeditor.com/docs/ckeditor5/latest/getting-started/setup/configuration.html | CKEditor documentation}
*/
export type EditorConfig = CKE5EditorConfig;
/**
* Styles applied globally to every editor instance.
*
* @remarks
*
* The `common` styles are applied first, followed by `light` or `dark` styles
* according to the preferences, and finally `additional` styles.
*/
export type Theme = {
/**
* Core styles.
*/
common?: EditorStyles;
/**
* Styles apllied in light mode.
*/
light?: EditorStyles;
/**
* Styles apllied in dark mode.
*/
dark?: EditorStyles;
/**
* Additional styles that complement the theme.
*/
additional?: EditorStyles;
};
/**
* Represents styles that can be applied to an editor instance.
* Can be a plain CSS string or an array of interpolations for dynamic styling.
*/
export type EditorStyles = string | Interpolation<object>[];
Adding a new preset [JS]
// src/admin/app.js
import {
Bold,
Italic,
Essentials,
Heading,
Image,
ImageCaption,
ImageStyle,
ImageToolbar,
ImageUpload,
Link,
List,
Paragraph,
} from 'ckeditor5';
import { setPluginConfig, StrapiMediaLib, StrapiUploadAdapter } from '@_sh/strapi-plugin-ckeditor';
const myCustomPreset = {
name: 'myCustomPreset',
description: 'myCustomPreset description',
editorConfig: {
licenseKey: 'GPL',
plugins: [
Bold,
Italic,
Essentials,
Heading,
Image,
ImageCaption,
ImageStyle,
ImageToolbar,
ImageUpload,
Link,
List,
Paragraph,
StrapiMediaLib,
StrapiUploadAdapter,
],
toolbar: [
'heading',
'|',
'bold',
'italic',
'link',
'bulletedList',
'numberedList',
'|',
'strapiMediaLib',
'|',
'undo',
'redo',
],
},
};
const myConfig = {
/**
* Note: Since the provided `presets` include only `myCustomPreset`
* this configuration will overwrite default presets.
*/
presets: [myCustomPreset],
};
export default {
register() {
setPluginConfig(myConfig);
},
};
Adding a new preset [TS]
// src/admin/app.tsx
import {
Bold,
Italic,
Essentials,
Heading,
Image,
ImageCaption,
ImageStyle,
ImageToolbar,
ImageUpload,
Link,
List,
Paragraph,
} from 'ckeditor5';
import {
type PluginConfig,
type Preset,
setPluginConfig,
StrapiMediaLib,
StrapiUploadAdapter,
} from '@_sh/strapi-plugin-ckeditor';
const myCustomPreset: Preset = {
name: 'myCustomPreset',
description: 'myCustomPreset description',
editorConfig: {
licenseKey: 'GPL',
plugins: [
Bold,
Italic,
Essentials,
Heading,
Image,
ImageCaption,
ImageStyle,
ImageToolbar,
ImageUpload,
Link,
List,
Paragraph,
StrapiMediaLib,
StrapiUploadAdapter,
],
toolbar: [
'heading',
'|',
'bold',
'italic',
'link',
'bulletedList',
'numberedList',
'|',
'strapiMediaLib',
'|',
'undo',
'redo',
],
},
};
const myConfig: PluginConfig = {
/**
* Note that since provided `presets` includes only `myCustomPreset`
* this configuration will overwrite default presets.
*/
presets: [myCustomPreset],
};
export default {
register() {
setPluginConfig(myConfig);
},
};
Default presets modification [TS]
// src/admin/app.tsx
import { css } from 'styled-components';
import {
type PluginConfig,
type Preset,
setPluginConfig,
defaultHtmlPreset,
defaultMarkdownPreset,
} from '@_sh/strapi-plugin-ckeditor';
const defaultHtml: Preset = {
...defaultHtmlPreset,
description: 'Modified default HTML editor',
styles: `
.ck {
color: red;
}
`,
editorConfig: {
...defaultHtmlPreset.editorConfig,
placeholder: 'Modified default HTML editor',
toolbar: [
'heading',
'|',
'bold',
'italic',
'link',
'bulletedList',
'numberedList',
'|',
'strapiMediaLib',
'insertTable',
'|',
'undo',
'redo',
],
},
};
const defaultMarkdown: Preset = {
...defaultMarkdownPreset,
description: 'Modified default Markdown editor',
styles: `
.ck {
--ck-editor-max-width: 1500px;
--ck-editor-min-height: 700px;
--ck-editor-max-height: 700px;
}
.ck.ck-editor__main {
border: 3px dashed ${({ theme }) => theme.colors.warning500};
}
`,
};
const myConfig: PluginConfig = {
presets: [defaultHtml, defaultMarkdown],
};
export default {
register() {
setPluginConfig(myConfig);
},
};
Modifying theme [TS]
// src/admin/app.tsx
import { css } from 'styled-components';
import { type PluginConfig, setPluginConfig, defaultTheme } from '@_sh/strapi-plugin-ckeditor';
const myConfig: PluginConfig = {
theme: {
...defaultTheme,
additional: css`
.ck {
--ck-editor-max-width: 1500px;
--ck-editor-min-height: 700px;
--ck-editor-max-height: 700px;
}
.ck.ck-editor__main {
border: 3px dashed ${({ theme }) => theme.colors.warning500};
}
`,
},
};
export default {
register() {
setPluginConfig(myConfig);
},
};
Adding Timestamp plugin [JS]
// src/admin/app.js
import { Plugin, ButtonView } from 'ckeditor5';
import { setPluginConfig, defaultHtmlPreset } from '@_sh/strapi-plugin-ckeditor';
class Timestamp extends Plugin {
init() {
const editor = this.editor;
editor.ui.componentFactory.add('timestamp', () => {
const button = new ButtonView();
button.set({
label: 'timestamp',
withText: true,
});
button.on('execute', () => {
const now = new Date();
editor.model.change(writer => {
editor.model.insertContent(writer.createText(now.toString()));
});
});
return button;
});
}
}
export default {
register() {
defaultHtmlPreset.editorConfig.plugins.push(Timestamp);
defaultHtmlPreset.editorConfig.toolbar.unshift('timestamp');
setPluginConfig({ presets: [defaultHtmlPreset] });
},
};
π Default HTML preset: admin/src/config/htmlPreset.ts
π Default Markdown preset: admin/src/config/markdownPreset.ts
π Default theme: admin/src/theme
π It is highly recommended to explore the official CKEditor5 documentation.
π‘ To display content from external sources, such as images or videos, in your admin panel, you need to configure your
middlewares.js
file. Check the documentation for details.
Feel free to fork the repository and open a pull request, any help is appreciated.
Follow these steps to set up a plugin development environment:
-
Clone the repository.
-
Navigate to the cloned plugin folder and install dependencies, run:
yarn install
-
Link the plugin to your project:
- In the plugin folder, run:
yarn watch:link
- Open a new terminal, navigate to your Strapi project directory, and run:
yarn dlx yalc add --link @_sh/strapi-plugin-ckeditor && yarn install
-
Rebuild the project and start the server:
yarn build
yarn develop
To upgrade to the latest version, follow the dedicated migration guide for detailed instructions.
v5.x.x
Strapi >= 5.0.0
Node >= 18.0.0 <= 22.x.x
v3.x.x
Strapi >= 4.13.0 < 5.0.0
Node >= 18.0.0 <= 20.x.x