Sign up (with export icon)

Integrating CKEditor 5 with Vue.js 3+ from npm

Contribute to this guide Show the table of contents

CKEditor 5 has an official Vue integration that you can use to add a rich text editor to your application. This guide will help you install it and configure to use the npm distribution of the CKEditor 5.

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

Quick start

Copy link

This guide assumes that you already have a Vue project. If you do not have one, see the Vue documentation to learn how to create it.

Start by installing the following packages:

ckeditor5 – contains all open-source plugins and features for CKEditor 5.

npm install ckeditor5
Copy code

ckeditor5-premium-features – contains premium plugins and features for CKEditor 5. Depending on your configuration and chosen plugins, you might not need it.

npm install ckeditor5-premium-features
Copy code

@ckeditor/ckeditor5-vue – the CKEditor 5 WYSIWYG editor component for Vue.

npm install @ckeditor/ckeditor5-vue
Copy code

With these packages installed, create a new Vue component called Editor.vue. It will use the <ckeditor> component to run the editor. The following example shows a single file component with open-source and premium CKEditor 5 plugins.

Note

Starting from version 44.0.0, the licenseKey property is required to use the editor. If you use a self-hosted editor from npm:

You can set up a free trial to test the editor and evaluate the self-hosting.

<template>
    <ckeditor
        v-model="data"
        :editor="ClassicEditor"
        :config="config"
    />
</template>

<script setup>
import { ref, computed } from 'vue';
import { ClassicEditor, Essentials, Paragraph, Bold, Italic } from 'ckeditor5';
import { FormatPainter } from 'ckeditor5-premium-features';
import { Ckeditor } from '@ckeditor/ckeditor5-vue';

import 'ckeditor5/ckeditor5.css';
import 'ckeditor5-premium-features/ckeditor5-premium-features.css';

const data = ref( '<p>Hello world!</p>' );

const config = computed( () => {
    return {
        licenseKey: '<YOUR_LICENSE_KEY>', // Or 'GPL'.
        plugins: [ Essentials, Paragraph, Bold, Italic, FormatPainter ],
        toolbar: [ 'undo', 'redo', '|', 'bold', 'italic', '|', 'formatPainter' ]
    };
} );
</script>
Copy code

Now, you can import and use the Editor.vue component anywhere in your application.

<template>
    <Editor />
</template>
Copy code

If you use Nuxt.js with server-side rendering enabled, remember to wrap the <Editor> component in the <ClientOnly> component to avoid issues with the editor calling browser-specific APIs on the server.

<template>
    <ClientOnly>
        <Editor />
    </ClientOnly>
</template>
Copy code

Component directives

Copy link

editor

Copy link

This directive specifies the editor to be used by the component. It must directly reference the editor constructor to be used in the template.

<template>
    <ckeditor :editor="ClassicEditor" />
</template>

<script setup>
import { ClassicEditor } from 'ckeditor5';
import { Ckeditor } from '@ckeditor/ckeditor5-vue';
</script>
Copy code

tag-name

Copy link

By default, the editor component creates a <div> container which is used as an element passed to the editor (for example, ClassicEditor#element). The element can be configured, so for example to create a <textarea>, use the following directive:

<ckeditor :editor="editor" tag-name="textarea" />
Copy code

v-model

Copy link

A standard directive for form inputs in Vue. Unlike model-value, it creates a two–way data binding, which:

  • Sets the initial editor content.
  • Automatically updates the state of the application as the editor content changes (for example, as the user types).
  • Can be used to set the editor content when necessary.
<template>
    <ckeditor :editor="ClassicEditor" v-model="data" />
    <button @click="emptyEditor">Empty the editor</button>

    <h2>Editor data</h2>
    <code>{{ data }}</code>
</template>

<script setup>
import { ref } from 'vue';
import { ClassicEditor } from 'ckeditor5';
import { Ckeditor } from '@ckeditor/ckeditor5-vue';

const data = ref( '<p>Hello world!</p>' );

function emptyEditor() {
    data.value = '';
}
</script>
Copy code

In the above example, the data property will be updated automatically as the user types and the content changes. It can also be used to change (as in emptyEditor()) or set the initial content of the editor.

If you only want to execute an action when the editor data changes, use the input event.

model-value

Copy link

Allows a one–way data binding that sets the content of the editor. Unlike v-model, the value will not be updated when the content of the editor changes.

<template>
    <ckeditor :editor="ClassicEditor" :model-value="data" />
</template>

<script setup>
import { ref } from 'vue';
import { ClassicEditor } from 'ckeditor5';
import { Ckeditor } from '@ckeditor/ckeditor5-vue';

const data = ref( '<p>Hello world!</p>' );
</script>
Copy code

To execute an action when the editor data changes, use the input event.

config

Copy link

Specifies the configuration of the editor.

<template>
    <ckeditor :editor="ClassicEditor" :config="config" />
</template>

<script setup>
import { computed } from 'vue';
import { ClassicEditor, Essentials, Paragraph, Bold, Italic } from 'ckeditor5';
import { Ckeditor } from '@ckeditor/ckeditor5-vue';

const config = computed( () => {
    return {
        licenseKey: '<YOUR_LICENSE_KEY>', // Or 'GPL'.
        plugins: [ Essentials, Paragraph, Bold, Italic ],
        toolbar: [ 'undo', 'redo', '|', 'bold', 'italic' ]
    };
} );
</script>
Copy code

disabled

Copy link

This directive controls the isReadOnly property of the editor.

It sets the initial read–only state of the editor and changes it during its lifecycle.

<template>
    <ckeditor :editor="ClassicEditor" :disabled="disabled" />
</template>

<script setup>
import { ref } from 'vue';
import { ClassicEditor } from 'ckeditor5';
import { Ckeditor } from '@ckeditor/ckeditor5-vue';

const disabled = ref( true );
</script>
Copy code

disableTwoWayDataBinding

Copy link

Allows disabling the two-way data binding mechanism. The default value is false.

The reason for introducing this option is performance issues in large documents. After enabling this flag, the v-model directive will no longer update the connected value whenever the editor’s data is changed.

This option allows the integrator to disable the default behavior and only call the editor.getData() method on demand, which prevents the slowdowns. You can read more in the relevant issue.

<ckeditor :editor="editor" :disableTwoWayDataBinding="true" />
Copy code

Component events

Copy link

ready

Copy link

Corresponds to the ready editor event.

<ckeditor :editor="editor" @ready="onEditorReady" />
Copy code

focus

Copy link

Corresponds to the focus editor event.

<ckeditor :editor="editor" @focus="onEditorFocus" />
Copy code

blur

Copy link

Corresponds to the blur editor event.

<ckeditor :editor="editor" @blur="onEditorBlur" />
Copy code

input

Copy link

Corresponds to the change:data editor event.

<ckeditor :editor="editor" @input="onEditorInput" />
Copy code

destroy

Copy link

Corresponds to the destroy editor event.

Note: Because the destruction of the editor is promise–driven, this event can be fired before the actual promise resolves.

<ckeditor :editor="editor" @destroy="onEditorDestroy" />
Copy code

How to?

Copy link

Using the Document editor type

Copy link

If you use the Document (decoupled) editor in your application, you need to manually add the editor toolbar to the DOM.

Since accessing the editor toolbar is not possible until after the editor instance is ready, put your toolbar insertion code in a method executed upon the ready event of the component, like in the following example:

<template>
    <ckeditor :editor="DecoupledEditor" @ready="onReady" />
</template>

<script setup>
import { DecoupledEditor } from 'ckeditor5';
import { Ckeditor } from '@ckeditor/ckeditor5-vue';

import 'ckeditor5/ckeditor5.css';

function onReady( editor )  {
    // Insert the toolbar before the editable area.
    editor.ui.getEditableElement().parentElement.insertBefore(
        editor.ui.view.toolbar.element,
        editor.ui.getEditableElement()
    );
}
</script>
Copy code

Using the editor with collaboration plugins

Copy link

We provide a ready-to-use integration featuring collaborative editing in a Vue application:

It is not mandatory to build applications on top of the above sample, however, it should help you get started.

Localization

Copy link

CKEditor 5 supports multiple UI languages, and so does the official Vue component. Follow the instructions below to translate CKEditor 5 in your Vue application.

Similarly to CSS style sheets, both packages have separate translations. Import them as shown in the example below. Then, pass them to the translations array inside the config prop in the component:


<script setup>
import { computed } from 'vue';
import coreTranslations from 'ckeditor5/translations/es.js';
import premiumFeaturesTranslations from 'ckeditor5-premium-features/translations/es.js';

const config = computed( () => {
    return {
        translations: [ coreTranslations, premiumFeaturesTranslations ],
        // Other configuration options
    };
} );
</script>
Copy code

For more information, refer to the Setting the UI language guide.

Jest testing

Copy link

You can use Jest as a test runner in Vue apps. Unfortunately, Jest does not use a real browser. Instead, it runs tests in Node.js that uses JSDOM. JSDOM is not a complete DOM implementation, and while it is sufficient for standard apps, it cannot polyfill all the DOM APIs that CKEditor 5 requires.

For testing CKEditor 5, it is recommended to use testing frameworks that utilize a real browser and provide a complete DOM implementation. Some popular options include:

These frameworks offer better support for testing CKEditor 5 and provide a more accurate representation of how the editor behaves in a real browser environment.

If this is not possible and you still want to use Jest, you can mock some of the required APIs. Below is an example of how to mock some of the APIs used by CKEditor 5:

import { TextEncoder } from 'util';

beforeAll( () => {
    window.TextEncoder = TextEncoder;

    window.scrollTo = jest.fn();

    window.ResizeObserver = class ResizeObserver {
        observe() {}
        unobserve() {}
        disconnect() {}
    };

    for (const key of ['InputEvent', 'KeyboardEvent']) {
        window[key].prototype.getTargetRanges = () => {
            const range = new StaticRange({
                startContainer: document.body.querySelector('.ck-editor__editable p')!,
                startOffset: 0,
                endContainer: document.body.querySelector('.ck-editor__editable p')!,
                endOffset: 0,
            });

            return [range];
        };
    }

    const getClientRects = () => ({
        item: () => null,
        length: 0,
        [Symbol.iterator]: function* () {}
    });

    Range.prototype.getClientRects = getClientRects;
    Element.prototype.getClientRects = getClientRects;

    if ( !Document.prototype.createElementNS ) {
        Document.prototype.createElementNS = ( namespace, name ) => {
            const element = document.createElement( name );
            element.namespaceURI = namespace;
            return element;
        };
    }
} );
Copy code

These mocks should be placed before the tests that use CKEditor 5. They are imperfect and may not cover all the cases, but they should be sufficient for basic initialization and rendering editor. Remember that they are not a replacement for proper browser testing.

Contributing and reporting issues

Copy link

The source code of this component is available on GitHub in https://github.com/ckeditor/ckeditor5-vue.

Next steps

Copy link