Integrating CKEditor 5 with Svelte from npm
Svelte is a modern JavaScript compiler that builds highly optimized, reactive web applications. Unlike traditional frameworks, Svelte shifts most of the work from runtime to build time, resulting in highly efficient applications. CKEditor 5 rich-text editor can be easily integrated with Svelte applications, providing powerful rich text editing capabilities to your projects.
This guide will show you how to integrate CKEditor 5 into a Svelte application using the npm distribution. If you are new to Svelte, check out their official tutorial.
First, create a new Svelte project using Vite:
npm create vite@latest ckeditor-svelte -- --template svelte
cd ckeditor-svelte
npm install
Next, install the ckeditor5 and the ckeditor5-premium-features packages:
npm install ckeditor5 ckeditor5-premium-features
The premium features package is optional and used in this guide to demonstrate a complete integration. You can use just the open-source features if you prefer.
When completed, the folder structure of your project should resemble this one:
├── node_modules/
├── public/
├── src/
│ ├── lib/
│ │ └── Editor.svelte
│ ├── App.svelte
│ ├── main.js
│ └── ...
├── index.html
├── package.json
├── vite.config.js
├── svelte.config.js
└── ...
The integration requires two key Svelte components:
src/lib/Editor.svelte– the component that wraps CKEditor functionalitysrc/App.svelte– the main application component that uses the Editor component
Let’s implement these components next.
Create a new file src/lib/Editor.svelte with the following content:
<script>
import { onMount, onDestroy } from 'svelte';
import { ClassicEditor, Essentials, Bold, Italic, Font, Paragraph } from 'ckeditor5';
import { FormatPainter } from 'ckeditor5-premium-features';
import 'ckeditor5/ckeditor5.css';
import 'ckeditor5-premium-features/ckeditor5-premium-features.css';
let { value = $bindable('') } = $props();
let editorContainer;
let editorInstance = $state(null);
let isDestroyed = false;
// Sync external value changes to the editor.
$effect(() => {
if (editorInstance && editorInstance.getData() !== value) {
editorInstance.setData(value);
}
});
onMount( async () => {
// Capture value before async initialization.
let initialData = value;
editorInstance = await ClassicEditor.create( editorContainer, {
licenseKey: '<YOUR_LICENSE_KEY>', // Replace with your license key
plugins: [ Essentials, Bold, Italic, Font, Paragraph, FormatPainter ],
toolbar: [
'undo', 'redo', '|', 'bold', 'italic', '|',
'fontSize', 'fontFamily', 'fontColor', 'fontBackgroundColor', '|',
'formatPainter'
],
initialData
} );
// Prevent memory leaks if unmounted during creation.
if (isDestroyed) {
await editorInstance.destroy();
return;
}
// Update the bound value when editor content changes.
editorInstance.model.document.on( 'change:data', () => {
value = editorInstance.getData();
} );
} );
onDestroy( () => {
// Clean up editor instance on unmount.
editorInstance?.destroy().catch( err => console.error( err ) );
editorInstance = null;
isDestroyed = true;
} );
</script>
<div bind:this={editorContainer}></div>
To listen for editor content changes, use the change:data event on editor.model.document as shown above. Do not use editor.on( 'change:data', ... ) directly on the editor instance – that listens for observable property changes on the editor object, not for content edits made by the user.
Now, modify the main App.svelte file to use our editor component:
<script>
import Editor from './lib/Editor.svelte';
let content = $state('<p>Enter your content here...</p>');
</script>
<main>
<h1>CKEditor 5 + Svelte</h1>
<div class="editor-wrapper">
<Editor bind:value={content} />
</div>
</main>
<style>
.editor-wrapper {
width: 800px;
}
:global(.ck.ck-editor__editable) {
height: 200px;
background-color: white;
color: #333;
}
</style>
You can now run the dev server to see the editor in action:
npm run dev
The Svelte HTML editor integration follows these key steps:
- Import dependencies: The required CKEditor 5 modules and styles are imported.
- Editor initialization: The editor is created with the specified configuration when the component mounts.
- Two-way data binding: The editor listens to
change:dataevents oneditor.model.documentto update the bound value, while a Svelte$effectsyncs external value changes back to the editor. - Cleanup: Resources are properly released when the component is destroyed.
Basic styling is provided in the App.svelte component to ensure proper display in various environments, especially when using dark themes:
.editor-wrapper {
width: 800px;
}
:global(.ck.ck-editor__editable) {
height: 200px;
background-color: white;
color: #333;
}
- Explore the Getting and setting data guide to learn how to handle content.
- Learn more about configuration options to customize your editor.
- Check the features documentation to add more functionality to your editor.