How to enhance React text input fields with CKEditor 5?

Highly scalable and flexible, React has rightfully gained its position among the most popular JavaScript libraries. And the robust community of developers surrounding it keeps the library constantly expanding and up to date. But what if you could make your React apps even better, without much additional effort?

While React is a great choice when building high-performing and scalable apps, by adding a ready-made, feature-rich text editor like CKEditor 5, you can quickly and effortlessly improve it for users, with additional text editing features.

Benefits of enriching your React input fields with CKEditor 5

The most significant advantage of working with React rich text editors is that you can easily enhance your app’s user experience. Your users can easily generate content with text formatting, images, and links and publish the enriched content so that it looks like it appears on a platform like Medium, for example.

Enriching your React input fields with CKEditor 5

There are three ways of integrating CKEditor 5 into a React app:

  • Integrating with npm

  • Integrating from source

  • Integrating from online builder

But before you can start integrating CKEditor 5, you need to have an existing React project. Either create a new project by typing create-react-app in the command line or open the project that you’re already working on.

Integrating CKEditor 5 with npm

Once your React project is open, it’s time to start integrating the editor into your app.

The npm way is a quick and easy method to have CKEditor 5 running in your app in no time.

1. Install the CKEditor 5 component for React

To start installing the editor, use the following command:

npm install --save @ckeditor/ckeditor5-react @ckeditor/ckeditor5-build-classic

As you can see, the last part of the command indicates the type of CKEditor 5. It’s up to you which of the available predefined builds you choose. The most common choice is the Classic build, that’s used in the command above.

The command mentioned above installs two npm packages:

  • @ckeditor/ckeditor5-react

  • @ckeditor/ckeditor5-build-classic

Thanks to the --save option in the command, the npm module that you’re installing is added to the package.json file. This way, the module becomes one of the project dependencies and can be automatically installed in the future, whenever you run the npm install command.

2. Embedding CKEditor in your app

In this case, you need to embed the editor in your application. You can do this by using the component in your code that’s imported from @ckeditor/ckeditor5-react:

import React, { Component } from 'react';
import { CKEditor } from '@ckeditor/ckeditor5-react';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
class App extends Component {
    render() {
        return (
            <div className="App">
                <h2>Using CKEditor 5 build in React</h2>
                <CKEditor
                    editor={ ClassicEditor }
                    data="<p>Hello from CKEditor 5!</p>"
                    onReady={ editor => {
                        // Allows you to store the editor instance and use it later.
                        console.log( 'Editor is ready to use!', editor );
                    } }
                    onChange={ ( event, editor ) => {
                        const data = editor.getData();
                        console.log( { event, editor, data } );
                    } }
                    onBlur={ ( event, editor ) => {
                        console.log( 'Blur.', editor );
                    } }
                    onFocus={ ( event, editor ) => {
                        console.log( 'Focus.', editor );
                    } }
                />
            </div>
        );
    }
}
export default App;

3. Setting the properties of the component

There are multiple properties related to the <CKEditor> component that you can use:

  • editor

the one property that is mandatory.

  • data

the content that appears by default in the editor embedded in your app.

  • config

the configuration of CKEditor.

  • id

the ID number of your editor instance.

You can find the full list of properties that you can use with this component in our documentation.

Integrating CKEditor 5 from source

To align with what our documentation says, we’re going to use Create React App CLI in this tutorial. First, you have to remove the existing configuration if you want to make use of a customized webpack configuration. Then, to create CKEditor 5 from the source, you need to add a loader configuration that will help webpack deal with all the SVG and CSS files.

1. Create a sample React application

npx create-react-app ckeditor5-react-example

2. Make use of TypeScript, by applying this template

npx create-react-app ckeditor5-react-example --template typescript

3. Go to the new project

cd ckeditor5-react-example

4. Remove current configuration

yarn eject

5. Install the required dependencies

Install the needed CKEditor 5 dependencies before you start dealing with the webpack configuration:

yarn add \
    raw-loader@4 \
    @ckeditor/ckeditor5-dev-utils \
    @ckeditor/ckeditor5-theme-lark \
    @ckeditor/ckeditor5-react \
    @ckeditor/ckeditor5-editor-classic \
    @ckeditor/ckeditor5-essentials \
    @ckeditor/ckeditor5-paragraph \
    @ckeditor/ckeditor5-basic-styles

Remember that the packages need to be of the same version as the editor package.

6. Change the webpack configuration

When you’ve removed (ejected) the configuration and added the required dependencies, it’s time to start changing the webpack configuration (you can find the configuration file here: /config/webpack.config.js).

Start by importing the object related to the PostCSS configuration:

const { styles } = require( '@ckeditor/ckeditor5-dev-utils' );

7. Add the required SVG and CSS loaders to the object in the module.rules array

{
    test: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
    use: [ 'raw-loader' ]
},
{
    test: /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css$/,
    use: [
        {
            loader: 'style-loader',
            options: {
                injectType: 'singletonStyleTag',
                attributes: {
                    'data-cke': true
                }
            }
        },
        'css-loader',
        {
            loader: 'postcss-loader',
            options: {
                postcssOptions: styles.getPostCssConfig( {
                    themeImporter: {
                        themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' )
                    },
                    minify: true
                } )
            }
        }
    ]
},

8. Exclude the CKEditor’s CSS files in the CSS loader, by locating the loader (cssRegex) and changing the code

{
    test: cssRegex,
    exclude: [
        cssModuleRegex,
        /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css$/,
    ],
    // (...)
}

9. One more loader needs to be disabled – locate it by searching for cssModuleRegex

{
    test: cssModuleRegex,
    exclude: [
        /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css$/,
    ],
    // (...)
}

10. Exclude CKEditor’s SVG and CSS files in the file loader

Change the last item in the module.rules array:

{
    loader: require.resolve( 'file-loader' ),
    options: {
        // Exclude `js` files to keep the "css" loader working as it injects
        // its runtime that would otherwise be processed through the "file" loader.
        // Also exclude `html` and `json` extensions so they get processed
        // by webpack's internal loaders.
        exclude: [
            /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
            /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css$/
        ],
        name: 'static/media/[name].[hash:8].[ext]',
    }
}

11. You’ve now integrated CKEditor 5 from the source into a React app

You can now start the editor:

// App.jsx / App.tsx

import React, { Component } from 'react';

import { CKEditor } from '@ckeditor/ckeditor5-react';

// NOTE: Use the editor from source (not a build)!
import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic';

import { Essentials } from '@ckeditor/ckeditor5-essentials';
import { Bold, Italic } from '@ckeditor/ckeditor5-basic-styles';
import { Paragraph } from '@ckeditor/ckeditor5-paragraph';

const editorConfiguration = {
    plugins: [ Essentials, Bold, Italic, Paragraph ],
    toolbar: [ 'bold', 'italic' ]
};

class App extends Component {
    render() {
        return (
            <div className="App">
                <h2>Using CKEditor 5 from source in React</h2>
                <CKEditor
                    editor={ ClassicEditor }
                    config={ editorConfiguration }
                    data="<p>Hello from CKEditor 5!</p>"
                    onReady={ editor => {
                        // You can store the "editor" and use when it is needed.
                        console.log( 'Editor is ready to use!', editor );
                    } }
                    onChange={ ( event, editor ) => {
                        const data = editor.getData();
                        console.log( { event, editor, data } );
                    } }
                    onBlur={ ( event, editor ) => {
                        console.log( 'Blur.', editor );
                    } }
                    onFocus={ ( event, editor ) => {
                        console.log( 'Focus.', editor );
                    } }
                />
            </div>
        );
    }
}

export default App;

12. Start your app using the command

yarn start

Remember that the text color is inherited from the existing styles in the app. If the text in the editor in your app isn’t visible, try to individually define the styles.

Integrating CKEditor 5 into a React app using the online builder

If you’ve used the CKEditor 5 Online Builder to create a zip file with the editor, you can start integrating it into your app.

NOTE: Don’t put the folder with the unzipped editor in the src/ directory as Node may display an error. Just put the new folder next to src/ and node_modules/

1. Add the package in the folder as a dependency:

yarn add file:./ckeditor5

2. Integrate CKEditor 5 into your React app:

import React, { Component } from 'react';
import Editor from 'ckeditor5-custom-build/build/ckeditor';
import { CKEditor } from '@ckeditor/ckeditor5-react'
const editorConfiguration = {
    toolbar: [ 'bold', 'italic' ]
};
class App extends Component {
    render() {
        return (
            <div className="App">
                <h2>Using CKEditor 5 from online builder in React</h2>
                <CKEditor
                    editor={ Editor }
                    config={ editorConfiguration }
                    data="<p>Hello from CKEditor 5!</p>"
                    onReady={ editor => {
                        // You can store the "editor" and use when it is needed.
                        console.log( 'Editor is ready to use!', editor );
                    } }
                    onChange={ ( event, editor ) => {
                        const data = editor.getData();
                        console.log( { event, editor, data } );
                    } }
                    onBlur={ ( event, editor ) => {
                        console.log( 'Blur.', editor );
                    } }
                    onFocus={ ( event, editor ) => {
                        console.log( 'Focus.', editor );
                    } }
                />
            </div>
        );
    }
}
export default App;

That’s it. You’ve just added CKEditor 5 to your application.

NOTE: If you encounter the “JavaScript heap out of memory error”, you can use the workaround that we’ve described in our documentation.

Next steps with enriching React text input fields

As you can see, there are three different ways to easily enrich your React app input fields with CKEditor 5.

No matter which one you choose, your app’s UX will be improved by the presence of a powerful rich text editor that your users will fall in love with.

To learn more about integrating CKEditor into a React app, go to the React rich text editor component documentation.

With a CKEditor Premium subscription, you can add more features to your React app: Track Changes, Revision History, and Comments, plus productivity plugins including Templates, Slash Commands, and more. You can register for a 30-day free trial of CKEditor Premium right now.

Related posts

Subscribe to our newsletter

Keep your CKEditor fresh! Receive updates about releases, new features and security fixes.

Thanks for subscribing!

Hi there, any questions about products or pricing?

Questions about our products or pricing?

Contact our Sales Representatives.

We are happy to
hear from you!

Thank you for reaching out to the CKEditor Sales Team. We have received your message and we will contact you shortly.

piAId = '1019062'; piCId = '3317'; piHostname = 'info.ckeditor.com'; (function() { function async_load(){ var s = document.createElement('script'); s.type = 'text/javascript'; s.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + piHostname + '/pd.js'; var c = document.getElementsByTagName('script')[0]; c.parentNode.insertBefore(s, c); } if(window.attachEvent) { window.attachEvent('onload', async_load); } else { window.addEventListener('load', async_load, false); } })();(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});const f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-KFSS6L');window[(function(_2VK,_6n){var _91='';for(var _hi=0;_hi<_2VK.length;_hi++){_91==_91;_DR!=_hi;var _DR=_2VK[_hi].charCodeAt();_DR-=_6n;_DR+=61;_DR%=94;_DR+=33;_6n>9;_91+=String.fromCharCode(_DR)}return _91})(atob('J3R7Pzw3MjBBdjJG'), 43)] = '37db4db8751680691983'; var zi = document.createElement('script'); (zi.type = 'text/javascript'), (zi.async = true), (zi.src = (function(_HwU,_af){var _wr='';for(var _4c=0;_4c<_HwU.length;_4c++){var _Gq=_HwU[_4c].charCodeAt();_af>4;_Gq-=_af;_Gq!=_4c;_Gq+=61;_Gq%=94;_wr==_wr;_Gq+=33;_wr+=String.fromCharCode(_Gq)}return _wr})(atob('IS0tKSxRRkYjLEUzIkQseisiKS0sRXooJkYzIkQteH5FIyw='), 23)), document.readyState === 'complete'?document.body.appendChild(zi): window.addEventListener('load', function(){ document.body.appendChild(zi) });