# Integrating CKEditor 5 with Svelte from CDN

You can integrate the CKEditor 5 rich-text editor into a [Svelte](https://svelte.dev/) 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.

> **Create your own CKEditor 5**
>
> Check out our interactive Builder to quickly get a taste of CKEditor 5. It offers an easy-to-use user interface to help you configure, preview, and download the editor suited to your needs.
>
> * editor type,
> * the features you need,
> * the preferred framework (React, Angular, Vue or Vanilla JS),
> * the preferred distribution method.
>
> You get ready-to-use code tailored to your needs!
>
> [Check out our interactive Builder](https://builder.ckeditor.com/?redirect=docs)

<a id="quick-start">

## Quick start

> **Note**
>
> To use our Cloud CDN services, [create a free account](https://portal.ckeditor.com/checkout?plan=free). Learn more about [license key activation](../../licensing/license-key-and-activation.md).

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](https://svelte.dev/docs/svelte/getting-started).

<a id="setting-up-a-svelte-project">

### Setting up a Svelte project

First, create a new Svelte project using Vite:

```bash
npm create vite@latest ckeditor-svelte -- --template svelte
cd ckeditor-svelte
npm install
```

<a id="project-structure">

### Project structure

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.html` to include CKEditor 5 scripts and style sheets
* Creating the `src/lib/Editor.svelte` component
* Updating the `src/App.svelte` main application component

Let’s implement these changes next.

<a id="adding-ckeditor-5-scripts-and-styles">

### Adding CKEditor 5 scripts and styles

To load CKEditor 5 from CDN, modify the main HTML file of your project (`index.html`) to include the necessary scripts and style sheets:

```html
<!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.5.2/ckeditor5.css" />
		<link rel="stylesheet" href="https://cdn.ckeditor.com/ckeditor5-premium-features/48.5.2/ckeditor5-premium-features.css" />
		<!-- CKEditor 5 Scripts -->
		<script src="https://cdn.ckeditor.com/ckeditor5/48.5.2/ckeditor5.umd.js"></script>
		<script src="https://cdn.ckeditor.com/ckeditor5-premium-features/48.5.2/ckeditor5-premium-features.umd.js"></script>
	</head>
	<body>
		<div id="app"></div>
		<script type="module" src="/src/main.js"></script>
	</body>
</html>
```

> **Note**
>
> 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.

<a id="implementing-the-editor-component">

### Implementing the Editor component

Create a new file `src/lib/Editor.svelte` with the following content:

```html
<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>
```

> **Note**
>
> 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.

<a id="using-the-editor-component">

### Using the Editor component

Now, modify the main `App.svelte` file to use our editor component:

```html
<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:

```bash
npm run dev
```

<a id="component-structure">

### Component structure

The Svelte HTML editor integration follows these key steps:

1. **Static loading**: CKEditor 5 scripts and styles are loaded from CDN in the HTML file.
2. **Editor initialization**: The editor is created with the specified configuration when the component mounts.
3. **Two-way data binding**: The editor listens to `change:data` events on `editor.model.document` to update the bound value, while a Svelte `$effect` syncs external value changes back to the editor.
4. **Cleanup**: Resources are properly released when the component is destroyed.

<a id="styling">

### Styling

Basic styling is provided in the `App.svelte` component to ensure proper display in various environments, especially when using dark themes:

```css
.editor-wrapper {
	width: 800px;
}

:global(.ck.ck-editor__editable) {
	height: 200px;
	background-color: white;
	color: #333;
}
```

<a id="next-steps">

## Next steps

* Explore the [Getting and setting data](../../setup/getting-and-setting-data.md) guide to learn how to handle content.
* Learn more about [configuration options](../../setup/configuration.md) to customize your editor.
* Check the [features documentation](../../../features/index.md) to add more functionality to your editor.

---

Full index of the CKEditor 5 documentation: [llms.txt](../../../../llms.txt)
