Setting up a basic rich text editor in React
Tags: react, tutorial, javascript
Published: 2020-09-17 21:44:08

As mentioned in my previous post, I've been working on a blogging app. I started writing up some posts of my own to document the experience, but quickly realized that the post content was not only plain-looking, but hard to read and unorganized. 

### Here's what my posts were looking like:

![An image of a blog post. It contains a list of items using whitespace and asterisks in an attempt to organize the content.](https://dev-to-uploads.s3.amazonaws.com/i/w8snazwsf3dkxlxe4q7w.png)

### Here's what I wanted them to look like!

![An image of a blog post that contains a list with bulletpoints, and the headers are bigger and bolded. Certain important words and phrases are bolded/italicized.](https://dev-to-uploads.s3.amazonaws.com/i/iya2g3tkcp8dz06ys3vi.png)

I did a lot of research trying to find a straightforward library that would let me achieve the above. In my case, [CKEditor 5](https://ckeditor.com/) ended up being the easiest to implement in my opinion. Out of the box it is very user-friendly and has a nice, minimal design. Some features I appreciate are keyboard shortcuts (like `Ctrl+B`/`CMD+B` for bold or `Ctrl+I`/`CMD+I` for italic) and auto-formatting. Here's how I was able to set up a very basic rich text editor using CKEditor.

## First up, choose your build

They have several different [build](https://ckeditor.com/docs/ckeditor5/latest/builds/guides/overview.html) options depending on what you're using it for, but in my case I used the Classic Build. Here's what the toolbar looks like: 

![CKEditor5's Classic Build toolbar](https://dev-to-uploads.s3.amazonaws.com/i/kgwadoo85i3iacroxbwo.png)

As you can see, it gives you the option to insert images, but you have to set up your own adapter to do so. I'll go over how to set that up in another post!

## Install CKEditor and your build

Using npm: 
```
npm install @ckeditor/ckeditor5-react @ckeditor/ckeditor5-build-classic --save
```

Or using yarn:
```
yarn add @ckeditor/ckeditor5-react @ckeditor/ckeditor5-build-classic
```

## Set up a component that will handle your form and text input

Import `CKEditor` and `ClassicEditor` (or whatever build you chose), then call on the `CKEditor` component inside your form. The component takes two necessary props: `editor` and `onChange`.

All you have to do is specify what build you're using in the `editor` prop, in this example it's `editor={ClassicEditor}`.

The `onChange` prop can be used to grab the stylized text. It uses a function that takes `event` and `editor`. We can use `editor.getData()` to grab that text. In my case, I'm storing it in my `body` state.

###### Note: For me, this component will be used in multiple parent components and I'm handling the form submission differently in each one, which is why I'm passing `onSubmit` as a prop. Your form submission might be different.


``` javascript
// TextEditor.js

import React, { useState } from 'react'
import CKEditor from '@ckeditor/ckeditor5-react'
import ClassicEditor from '@ckeditor/ckeditor5-build-classic'

const TextEditor = ({ onSubmit }) => {
	const [body, setBody] = useState('')

	const handleSubmit = (e) => {
		e.preventDefault()
		onSubmit({ body })
	}

	return (
		<form onSubmit={handleSubmit}>
			<CKEditor
				editor={ClassicEditor}
				onChange={(event, editor) => {
					const data = editor.getData()
					setBody(data)
				}}
			/>
			<button type='submit'>Submit</button>
		</form>
	)
}

export default TextEditor
```

That's all you need to have a simple working rich text editor using React and CKEditor 5. The data I'm storing in `body` is in HTML, so if you want to display the output elsewhere you need to use [dangerouslySetInnerHTML](https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml). Keep reading if you want to configure the toolbar plugins!

## Configuring the toolbar plugins

Let's say you just want a very basic editor, and don't want to have the option to insert tables or images/media. In that case, you can set up a configuration object and pass it to your build's `defaultConfig`. You can also use this to separate the different sections and further personalize the toolbar to your needs.

``` javascript
// editorConfig.js

export const config = {
	toolbar: {
		items: [
			'bold',
			'italic',
			'|',
			'bulletedList',
			'numberedList',
			'indent',
			'outdent',
			'|',
			'heading',
			'|',
			'undo',
			'redo'
		]
	}
}
```

Once the config is set up, I'm just importing it into my TextEditor file. Inside the component before the return statement, just pass the config in with `ClassicEditor.defaultConfig = config`.

``` javascript
// TextEditor.js

import React, { useState } from 'react'
import CKEditor from '@ckeditor/ckeditor5-react'
import ClassicEditor from '@ckeditor/ckeditor5-build-classic'

// import the config here
import { config } from './editorConfig'

const TextEditor = ({ onSubmit }) => {
    const [body, setBody] = useState('')

        // and then plug it in here
	ClassicEditor.defaultConfig = config

	const handleSubmit = (e) => {
		// ...
	}

	return (
		// ...
	)
}

export default TextEditor
```

And that's it! Here's what mine looks like in my app:

![The 'Create New Post' page of my app. Shows the CKEditor toolbar and some sample text that display it's usage.](https://dev-to-uploads.s3.amazonaws.com/i/u8s2myxkb7mjrb9rikp3.png)

Thanks for reading 😄