This year at React Conf, Facebook open-sourced a game changing project called Draft.js. This is a very powerful engine that allows developers to create and fine-tune our very own text editor without all the hassle of handling a ContentEditable with our bare hands.

The video is 25 minutes long and unless you’re in a hurry, I highly recommend watching it because it highlights a lot of the issues that come with designing a rich text editor in today’s modern web.

Since the announcement was only a few weeks ago, a lot of the documentation and official pages can feel very lacking. I know I certainly struggled with the basics myself.

That is why I am presenting you with a short (yet detailed) tutorial on getting started with Draft.js. By the end of this article, you’ll learn how to create a Draft.js editor and add a button to make text bold.

If there’s enough interest, I’ll write a second part to this tutorial where I’ll dive deeper into all the powerful things that Draft.js allows us to do.

Let’s get started!

Let’s Have Brunch

I know you probably prefer to use Webpack or Browserify to build your React projects, but I’d like to encourage you to try my favourite build tool instead: Brunch.

Brunch is one of the simplest build tools I have ever used. Please just give it a chance before screaming javascript fatigue over and over again.

I’ve always hated how much configuration Webpack required, and I’m going to show you how nice it is to use a zero-config build tool by comparison.

Let’s install Brunch:

npm install -g brunch

And create our project from the React skeleton:

brunch new draftjs-tutorial -s react

Once that’s done, let’s move into the directory and fire up the dev server:

cd draftjs-tutorial

npm start

That’s it! You should now be able to go to http://localhost:3333/ in your browser and see something like this:

Wasn’t that fast? (P.S. Don’t mind my custom font)

If you look inside the project folder, you’ll see that there is an App.jsx file inside the /app/components/ directory. That’s where we will be spending most of our time.

As we save files here, Brunch will watch for changes and refresh the page to reflect those changes.

Basic Styles

Before we get started with Draft.js itself, let’s set some basic CSS styles. In the /app/styles/ directory, find application.css and replace its content with this:

* {

box-sizing: border-box;

} #content {

width: 480px;

margin: 0 auto;

} .editor {

border: 1px solid grey;

padding: 6px;

}

Simple enough, right? We won’t have to touch CSS for the remainder of this tutorial.

Setting Up Draft.js

Now that we have our project ready, let’s actually start by adding Draft.js:

npm install --save draft-js

Once that’s done, open up the App.jsx file I mentioned above (it’s located in the /app/components/ directory). First, let’s remove all of the auto-generated stuff so we’re left with this blank React component:

import React from ‘react’; export default class App extends React.Component {

render() {

return (

<div id=”content”>

</div>

);

}

}

Now add some basic markup into our render() function as we prepare to drop in our Draft.js stuff:

render() {

return (

<div id=”content”>

<h1>Draft.js Editor</h1>

<div className=”editor”>

<Editor

editorState={this.state.editorState}

onChange={this.onChange}

/>

</div>

</div>

);

}

Are you worried about that Editor component? No worries, that’s what we’re going to talk about next!

Editor and EditorState

Add the import statement at the top so we can use Draft.js:

import {Editor, EditorState} from ‘draft-js’;

We’re going to need two things here, the Editor component (the thing we will put inside our render function) and also the EditorState object (the object that represents the state of our editor).

With Draft.js, the parent component (in our case: App.jsx) controls the state of the editor by holding the EditorState object inside its local component state. This means that we should initialize our component with an empty state to begin with:

this.state = {editorState: EditorState.createEmpty()};

Since we’ll need to make sure that this.state.editorState is up-to-date with what’s happening inside the Editor, we’ll need to tell the Editor to update our state whenever something changes.

To do this, we’ll create a function called onChange() and we’ll send it down to the Editor as a prop. Let’s also create this function in our constructor:

this.onChange = (editorState) => this.setState({editorState});

And finally, this is what your App.jsx file should look like:

import React from ‘react’;

import {Editor, EditorState} from ‘draft-js’; export default class App extends React.Component {

constructor(props) {

super(props);

this.state = {editorState: EditorState.createEmpty()};

this.onChange = (editorState) => this.setState({editorState});

} render() {

return (

<div id=”content”>

<h1>Draft.js Editor</h1>

<div className=”editor”>

<Editor

editorState={this.state.editorState}

onChange={this.onChange}

/>

</div>

</div>

);

}

}

Up and Running

There you go, that’s all you need to get a Draft.js editor up and running! You can now type inside it just like a regular ContentEditable. But of course, nothing special is happening yet. We haven’t even done anything beyond what an ordinary ContentEditable could do.

Be Bold

Okay, small steps. Let’s add a button that can make the highlighted text bold. To do that, we’re going to need to borrow from the RichUtils module. So let’s add that to the import statement at the top:

import {Editor, EditorState, RichUtils} from ‘draft-js’;

Now, we’ll make a click handler inside of our class:

_onBoldClick() {

this.onChange(RichUtils.toggleInlineStyle(

this.state.editorState,

‘BOLD’

));

}

And we’ll also add a button in our render() function to trigger this handler:

<button onClick={this._onBoldClick.bind(this)}>Bold</button>

This is what your App.jsx file should look like now:

import React from ‘react’;

import {Editor, EditorState, RichUtils} from ‘draft-js’; export default class App extends React.Component {

constructor(props) {

super(props);

this.state = {editorState: EditorState.createEmpty()};

this.onChange = (editorState) => this.setState({editorState});

} _onBoldClick() {

this.onChange(RichUtils.toggleInlineStyle(

this.state.editorState,

‘BOLD’

));

} render() {

return (

<div id=”content”>

<h1>Draft.js Editor</h1>

<button onClick={this._onBoldClick.bind(this)}>Bold</button>

<div className=”editor”>

<Editor

editorState={this.state.editorState}

onChange={this.onChange}

/>

</div>

</div>

);

}

}

That’s it. You can go to http://localhost:3333/ and try it out yourself. Of course, this is a super simple example, but we’re just getting started.

Next Time

Join us next time when I’ll show you how to implement hashtags that are coloured red as you type them. We will be making use of the very important decorator system that Draft.js brings us.

We’ll also talk about the Entity system and how we can leverage that to make even more powerful elements for the Draft.js editor. In order to prepare for that, you may want to read the API docs or this handy Medium post by rajaraodv.

By that point, you’ll probably be thinking that Draft.js requires a lot of work!

Well, have no worries because, after our discussion on those topics, we will dive into draft-js-plugins, which is a plugin architecture for Draft.js. This makes it mind-numbingly easy for us to share and integrate new features into our Draft.js editors.