React rich text editor component (CDN)
CKEditor 5 has an official React 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 CDN distribution of the CKEditor 5.
CKEditor 5 Builder
In our interactive Builder you can 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. You can easily select:
- The editor type.
- The features you need.
- Preferred framework (React, Angular, Vue or Vanilla JS).
- Preferred distribution method.
At the end you get ready-to-use code tailored to your needs!
# Quick start
This guide assumes that you already have a React project. If you do not have one, see the React documentation to learn how to create it.
To use our Cloud CDN services, create a free account. Learn more about license key activation.
Start by installing the React integration for CKEditor 5 from npm:
npm install @ckeditor/ckeditor5-react
Once the integration is installed, create a new React component called Editor.jsx
. It will use the useCKEditorCloud
helper to load the editor code from the CDN and the <CKEditor>
component to run it, both of which come from the above package. The following example shows a component with open source and premium CKEditor 5 plugins.
import React from 'react';
import { CKEditor, useCKEditorCloud } from '@ckeditor/ckeditor5-react';
const CKEditorDemo = () => {
const cloud = useCKEditorCloud( {
version: '44.0.0',
premium: true
} );
if ( cloud.status === 'error' ) {
return <div>Error!</div>;
}
if ( cloud.status === 'loading' ) {
return <div>Loading...</div>;
}
const {
ClassicEditor,
Essentials,
Paragraph,
Bold,
Italic
} = cloud.CKEditor;
const { FormatPainter } = cloud.CKEditorPremiumFeatures;
return (
<CKEditor
editor={ ClassicEditor }
data={ '<p>Hello world!</p>' }
config={ {
licenseKey: '<YOUR_LICENSE_KEY>',
plugins: [ Essentials, Paragraph, Bold, Italic, FormatPainter ],
toolbar: [ 'undo', 'redo', '|', 'bold', 'italic', '|', 'formatPainter' ]
} }
/>
);
};
In the above example, the useCKEditorCloud
helper is used to load the editor code and plugins from CDN. The premium
option is set to also load premium plugins. For more information about the useCKEditorCloud
helper, see the Loading CDN resources guide.
# Component properties
The <CKEditor>
component supports the following properties:
editor
(required) – TheEditor
constructor to use.data
– The initial data for the created editor. See the Getting and setting data guide.config
– The editor configuration. See the Configuration guide.id
– The editor ID. When this property changes, the component restarts the editor with new data instead of setting it on an initialized editor.disabled
– A Boolean value. Theeditor
is being switched to read-only mode if the property is set totrue
.disableWatchdog
– A Boolean value. If set totrue
, the watchdog feature will be disabled. It is set tofalse
by default.watchdogConfig
– Configuration object for the watchdog feature.onReady
– A function called when the editor is ready with aneditor
instance. This callback is also called after the reinitialization of the component if an error occurred.onAfterDestroy
– A function called after the successful destruction of an editor instance rendered by the component. This callback is also triggered after the editor has been reinitialized after an error. The component is not guaranteed to be mounted when this function is called.onChange
– A function called when the editor data has changed. See theeditor.model.document#change:data
event.onBlur
– A function called when the editor was blurred. See theeditor.editing.view.document#blur
event.onFocus
– A function called when the editor was focused. See theeditor.editing.view.document#focus
event.onError
– A function called when the editor has crashed during the initialization or during the runtime. It receives two arguments: the error instance and the error details. Error details is an object that contains two properties:phase
:'initialization'|'runtime'
– Informs when the error has occurred (during or after the editor/context initialization).willEditorRestart
– Whentrue
, it means the editor component will restart itself.
The editor event callbacks (onChange
, onBlur
, onFocus
) receive two arguments:
# Context feature
The @ckeditor/ckeditor5-react
package provides a ready-to-use component for the context feature that is useful to use with some CKEditor 5 collaboration features.
import React from 'react';
import { CKEditor, CKEditorContext, useCKEditorCloud } from '@ckeditor/ckeditor5-react';
export const CKEditorCloudContextDemo = () => {
const cloud = useCKEditorCloud( {
version: '44.0.0'
} );
if ( cloud.status === 'error' ) {
return <div>Error!</div>;
}
if ( cloud.status === 'loading' ) {
return <div>Loading...</div>;
}
const { ClassicEditor } = cloud.CKEditor;
return (
<CKEditorContext
context={ ClassicEditor.Context }
contextWatchdog={ ClassicEditor.ContextWatchdog }
onChangeInitializedEditors={ editors => {
console.log( 'Initialized editors:', editors );
} }
>
<CKEditorNestedInstanceDemo
name='editor1'
content='<p>Editor 1</p>'
/>
<br />
<CKEditorNestedInstanceDemo
name='editor2'
content='<p>Editor 2</p>'
/>
</CKEditorContext>
);
};
function CKEditorNestedInstanceDemo( { name, content } ) {
const cloud = useCKEditorCloud( {
version: '44.0.0',
premium: true
} );
if ( cloud.status === 'error' ) {
console.error( cloud );
return <div>Error!</div>;
}
if ( cloud.status === 'loading' ) {
return <div>Loading...</div>;
}
const {
ClassicEditor,
Essentials,
Paragraph,
Bold,
Italic,
Mention
} = cloud.CKEditor;
return (
<CKEditor
contextItemMetadata={ {
name
} }
editor={ ClassicEditor }
data={ content }
config={ {
plugins: [
Essentials,
Paragraph,
Bold,
Italic,
Mention
],
toolbar: {
items: [ 'undo', 'redo', '|', 'bold', 'italic' ],
}
} }
/>
);
}
The CKEditorContext
component supports the following properties:
context
(required) – The CKEditor 5 context class.contextWatchdog
(required) – The Watchdog context class.config
– The CKEditor 5 context configuration.isLayoutReady
– A property that delays the context creation when set tofalse
. It creates the context and the editor children once it istrue
or unset. Useful when the CKEditor 5 annotations or a presence list are used.id
– The context ID. When this property changes, the component restarts the context with its editor and reinitializes it based on the current configuration.onChangeInitializedEditors
– A function called when any editor is initialized or destroyed in the tree. It receives a dictionary of fully initialized editors, where the key is the value of thecontextItemMetadata.name
property set on theCKEditor
component. The editor’s ID is the key if thecontextItemMetadata
property is absent. Additional data can be added to thecontextItemMetadata
in theCKEditor
component, which will be passed to theonChangeInitializedEditors
function.onReady
– A function called when the context is ready and all editors inside were initialized with thecontext
instance. This callback is also called after the reinitialization of the component if an error has occurred.onError
– A function called when the context has crashed during the initialization or during the runtime. It receives two arguments: the error instance and the error details. Error details is an object that contains two properties:phase
:'initialization'|'runtime'
– Informs when the error has occurred (during or after the editor/context initialization).willContextRestart
– Whentrue
, it means that the context component will restart itself.
An example build that exposes both context and classic editor can be found in the CKEditor 5 collaboration sample.
# How to?
# Using the document editor type
If you use the document (decoupled) editor, you need to add the toolbar to the DOM manually:
import { useEffect, useRef, useState } from 'react';
import { CKEditor } from '@ckeditor/ckeditor5-react';
function App() {
const cloud = useCKEditorCloud( {
version: '44.0.0'
} );
const editorToolbarRef = useRef( null );
const [ isMounted, setMounted ] = useState( false );
useEffect( () => {
setMounted( true );
return () => {
setMounted( false );
};
}, [] );
if ( cloud.status === 'error' ) {
console.error( cloud );
return <div>Error!</div>;
}
if ( cloud.status === 'loading' ) {
return <div>Loading...</div>;
}
const { DecoupledEditor, Essentials, Paragraph, Bold, Italic } = cloud.CKEditor;
return (
<div>
<div ref={ editorToolbarRef }></div>
<div>
{ isMounted && (
<CKEditor
editor={ DecoupledEditor }
data='<p>Hello from CKEditor 5 decoupled editor!</p>'
config={ {
plugins: [ Essentials, Paragraph, Bold, Italic ],
toolbar: [ 'undo', 'redo', '|', 'bold', 'italic' ]
} }
onReady={ ( editor ) => {
if ( editorToolbarRef.current ) {
editorToolbarRef.current.appendChild( editor.ui.view.toolbar.element );
}
}}
onAfterDestroy={ ( editor ) => {
if ( editorToolbarRef.current ) {
Array.from( editorToolbarRef.current.children ).forEach( child => child.remove() );
}
} }
/>
) }
</div>
</div>
);
}
export default App;
# Using the editor with collaboration plugins
We provide a few ready-to-use integrations featuring collaborative editing in React applications:
- CKEditor 5 with real-time collaboration features
- CKEditor 5 with real-time collaboration and revision history features
- CKEditor 5 with the revision history feature
- CKEditor 5 with the track changes feature
It is not mandatory to build applications on top of the above samples, however, they should help you get started.
# Localization
CKEditor 5 supports multiple UI languages, and so does the official React component. To translate the editor, pass the languages you need into the translations
array inside the configuration of the useCKEditorCloud
hook.
import React from 'react';
import { CKEditor, useCKEditorCloud } from '@ckeditor/ckeditor5-react';
const CKEditorDemo = () => {
const cloud = useCKEditorCloud( {
version: '44.0.0',
translations: [ 'es' ]
} );
if ( cloud.status === 'error' ) {
return <div>Error!</div>;
}
if ( cloud.status === 'loading' ) {
return <div>Loading...</div>;
}
const {
ClassicEditor,
Essentials,
Bold,
Italic,
Paragraph
} = cloud.CKEditor;
return (
<CKEditor
editor={ ClassicEditor }
data={ '<p>Hello world!</p>' }
config={ {
licenseKey: '<YOUR_LICENSE_KEY>',
toolbar: [ 'undo', 'redo', '|', 'bold', 'italic' ],
plugins: [ Bold, Essentials, Italic, Paragraph ],
} }
/>
);
};
For more information, please refer to the Setting the UI language guide.
# TypeScript support
The official React integration for CKEditor 5 is written in TypeScript and fully supports it. If you use TypeScript in your project, you can use the CKEditor
component without additional configuration. However, if you want to use some specific types from the CKEditor 5 packages, you can import them directly from a special package containing type definitions. Take a look at the following example:
import React from 'react';
import { CKEditor, useCKEditorCloud } from '@ckeditor/ckeditor5-react';
import type { EventInfo } from 'https://cdn.ckeditor.com/typings/ckeditor5.d.ts';
const CKEditorDemo = () => {
const cloud = useCKEditorCloud( {
version: '44.0.0',
translations: [ 'es' ]
} );
if ( cloud.status === 'error' ) {
return <div>Error!</div>;
}
if ( cloud.status === 'loading' ) {
return <div>Loading...</div>;
}
const {
ClassicEditor,
Essentials,
Bold,
Italic,
Paragraph
} = cloud.CKEditor;
return (
<CKEditor
editor={ ClassicEditor }
data={ '<p>Hello world!</p>' }
config={ {
licenseKey: '<YOUR_LICENSE_KEY>',
toolbar: [ 'undo', 'redo', '|', 'bold', 'italic' ],
plugins: [ Bold, Essentials, Italic, Paragraph ],
} }
onBlur={ ( event: EventInfo ) => {
// your event handler
} }
/>
);
};
In the example above, the EventInfo
type is imported from the https://cdn.ckeditor.com/typings/ckeditor5.d.ts
package, while the editor itself loads from the CDN. Note that https://cdn.ckeditor.com/typings/ckeditor5.d.ts
is not an actual URL to the CKEditor 5 typings file but a synthetic TypeScript module providing typings for the editor. The ckeditor5
package supplies the actual types, which depend on the @ckeditor/ckeditor5-react
package.
Although this setup might seem complex, it prevents users from directly importing anything from the ckeditor5
package, which could lead to duplicated code issues.
# Type definitions for premium features
If you want to use types for premium features, you can import them similarly to the base editor types. Remember that you need to install the ckeditor5-premium-features
package to use them. You can do it by running the following command:
npm install --save-dev ckeditor5-premium-features
After installing the package, you can import the types in the following way:
<script setup>
// ...
import type { Mention } from 'https://cdn.ckeditor.com/typings/ckeditor5-premium-features.d.ts';
// ...
</script>
# Known issues
While type definitions for the base editor should be available out of the box, some bundlers do not install the ckeditor5
package, which provides typing for the editor. If you encounter any issues with the type definitions, you can install the ckeditor5
package manually:
npm install --save-dev ckeditor5
# Contributing and reporting issues
The source code of rich text editor component for React is available on GitHub in https://github.com/ckeditor/ckeditor5-react.
Every day, we work hard to keep our documentation complete. Have you spotted outdated information? Is something missing? Please report it via our issue tracker.
With the release of version 42.0.0, we have rewritten much of our documentation to reflect the new import paths and features. We appreciate your feedback to help us ensure its accuracy and completeness.