Creating a rich text editor - Part 2 - Text Styling
6 mins read
In the first part of the tutorial, we built the simplest form of the text editor where we can just type some text. In this part, we will be adding features to add basic text styling to the characters.
We will start by adding a functionality where one can add bold, italic and underline styles to selected text by pressing the stand keyboard shortcuts for those, i.e
| Mac | Windows/Linux | Action |
|---|---|---|
| CMD+B | CTRL+B | Bold |
| CMD+I | CTRL+I | Italic |
| CMD+U | CTRL+U | Uunderline |
We are using draft-js-plugins editor which allows us to build various plugins and pass them to the Editor component. We can choose to either create a single plugin with all the functionalities in it or build multiple plugins with single functionality in each. For this tutorial, we will be following the latter approach.
There are various handlers and properties that the Editor component can be passed for different kind of events. You can read the documentation here. draft-js-editor helps us in using these handlers in each of the plugins that we create.
The way Draft-js works is that instead of directly relying on browser’s contenteditable API, it treats each keypress as an input. Then it analyzes the key combination and based on that it generates an output and renders it in the contenteditable. Internally, on each keypress, a string signal is generated which is then analyzed and output is rendered.
Now that we have understood how draft-js works, let’s start by creating a plugin that handles keyboard shortcuts mentioned above. Draft-js has a utility method that detects common key combinations and emits desired signal strings. For example, when CMD+B is pressed on Mac, it emits string - bold. So we will be using this utility method to add basic styling to text using keyboard.
Simplest draft-plugin-plugin is just on object with all or some of the handlers that you want to use. We will be using the keyBindingFn handler of Editor to add B, I, U styling. Let’s start by creating a plugins directory inside src. Now create a file called basicTextStylePlugin.js inside plugins and add the following code –
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import {
getDefaultKeyBinding,
RichUtils,
} from 'draft-js';
const basicTextStylePlugin = {
keyBindingFn(event) {
return getDefaultKeyBinding(event);
},
handleKeyCommand(command, { getEditorState, setEditorState }) {
const editorState = getEditorState();
const newEditorState = RichUtils.handleKeyCommand(
editorState, command
);
if (newEditorState) {
setEditorState(newEditorState);
return 'handled';
}
return 'not-handled';
}
};
export default basicTextStylePlugin;
Above code creates the simplest form of draft-js-plugins where it is an object with the handlers to use, here, the handlers are keyBindingFn and handleKeyCommand. In each of the method of draft-js-plugins, besides the default argument passed by draft-jss Editor component, a second argument is also passed which is an object that has the getEditorState and setEditorState methods which we are using in handleKeyCommand to modify the content.
keyBindingFntakes the keyboard inputeventobject and passes it togetDefaultKeyBindingutility function ofdraft-js, and returns the resultant string. In this case, when one presses CMD+B, it returnsbold.handleKeyCommandis called whenever a string signal is emitted. In this case, when we returnboldstring fromkeyBindingFn, it is passed ontohandleKeyCommand. In this method, we can analyse the command string and perform actions based on that. Since we are just using internal command ofdraft-js, we won’t be doing any extra checks right now. We will useRichUtilsobject ofdraft-jswhich takes as input, theeditorStateand the stringcommandand returns the modifiededitorState. We use thesetEditorStatemethod to update our content after modification. We return ahandledstring if we have modified the contents on our own and don’t wantdraft-jsto apply the default behaviour. Otherwise we returnnot-handledso that other plugins, if any, can do their modifications.
Now, let us use this basicTextStylePlugin in our MyEditor component of src/App.js. Before proceeding, lets change the name of our files to reflect the names of the components they have. Change the name of src/App.js to src/MyEditor.js, src/App.css to src/MyEditor.css. Let’s also updated the file refernces. In src/MyEditor.js update the import of App.css to MyEditor.css and update index.js to –
1
2
3
4
5
6
7
8
9
import React from 'react';
import ReactDOM from 'react-dom';
import MyEditor from './MyEditor';
import './index.css';
ReactDOM.render(
<MyEditor />,
document.getElementById('root')
);
At this point, your directory structure will look like this –

Now, let’s start using the newly created plugin. Open src/MyEditor.js and modify the contents (modified lines are just below the inline comments) –
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import 'draft-js/dist/Draft.css';
import './MyEditor.css';
import React from 'react';
import { EditorState } from 'draft-js';
import Editor from 'draft-js-plugins-editor';
/* Import the `basicTextStylePlugin` */
import basicTextStylePlugin from './plugins/basicTextStylePlugin';
class MyEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty(),
};
/* Create an array of plugins to be passed to `Editor` */
this.plugins = [
basicTextStylePlugin,
];
}
componentDidMount() {
this.focus();
}
onChange = (editorState) => {
this.setState({
editorState,
});
}
focus = () => {
this.editor.focus();
}
render() {
const { editorState } = this.state;
return (
<div className="editor" onClick={this.focus}>
<Editor
editorState={editorState}
onChange={this.onChange}
plugins={this.plugins} // Pass the plugins to the Editor
ref={(element) => { this.editor = element; }}
placeholder="Tell your story"
spellCheck
/>
</div>
);
}
}
export default MyEditor;
Now, you can open your dev server @ http://localhost:3000 where you will be able to select some typed text and press CMD+B to make the selected text bold.

At this point or even at the end of previous tutorial, you may have gotten a warning message in the console like this Warning: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead.. This is because we are using the latest version of React from which PropTypes have been removed to another package called prop-types and other libraries (draft-js and draft-js-plugins) are using the old PropTypes. This is nothing to be worried about.
This completes the 2nd part of the tutorial. In next part, we will learn about entities and implement adding a link to the selected text.
You can get the source code from this GitHub repo . The code for this tutorial can be run from the part2 tag. After cloning the repo, you can do
git checkout part2
List of tutorials in this series –
- Part 1 - Barebones Editor
- Part 2 - Text Styling
- Part 3 - Entities and decorators