Integrating CKEditor 5 with Svelte from CDN
You can integrate the CKEditor 5 rich-text editor into a Svelte application by loading CKEditor 5 from the CDN and initializing the editor inside your own Svelte component. There is no dedicated Svelte component for CKEditor 5, so you create the editor when the component mounts and destroy it when it unmounts.
To use our Cloud CDN services, create a free account. Learn more about license key activation.
This guide will show you how to integrate CKEditor 5 into a Svelte application using the CDN 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
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:
- Modifying
index.htmlto include CKEditor 5 scripts and style sheets - Creating the
src/lib/Editor.sveltecomponent - Updating the
src/App.sveltemain application component
Let’s implement these changes next.
To load CKEditor 5 from CDN, modify the main HTML file of your project (index.html) to include the necessary scripts and style sheets:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CKEditor 5 + Svelte</title>
<!-- CKEditor 5 CSS -->
<link rel="stylesheet" href="https://cdn.ckeditor.com/ckeditor5/48.3.0/ckeditor5.css" />
<link rel="stylesheet" href="https://cdn.ckeditor.com/ckeditor5-premium-features/48.3.0/ckeditor5-premium-features.css" />
<!-- CKEditor 5 Scripts -->
<script src="https://cdn.ckeditor.com/ckeditor5/48.3.0/ckeditor5.umd.js"></script>
<script src="https://cdn.ckeditor.com/ckeditor5-premium-features/48.3.0/ckeditor5-premium-features.umd.js"></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
The premium features scripts and style sheets are optional and used in this guide to demonstrate a complete integration. You can use just the open-source features if you prefer.
Create a new file src/lib/Editor.svelte with the following content:
<script>
import { onMount, onDestroy } from 'svelte';
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 () => {
const { ClassicEditor, Essentials, Bold, Italic, Font, Paragraph } = CKEDITOR;
const { FormatPainter } = CKEDITOR_PREMIUM_FEATURES;
// Capture value before async initialization.
let initialData = value;
editorInstance = await ClassicEditor.create( {
attachTo: 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'
],
root: {
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:
- Static loading: CKEditor 5 scripts and styles are loaded from CDN in the HTML file.
- 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.