$Rich$ Text <Editor/>

Jesse Billard
Sep 9, 2018 · 7 min read

I use a list making app called Workflowy on the daily. It’s clean, simple design is both powerful and easy to use. In the b.c. (before coding) period of my life, I was blissfully ignorant to the difficulty of building something as seemingly “simple” as a list making app like Workflowy. Now in the a.d. (always developing) period of my life, my curiosity led me down the path of today’s topic…Rich Text Editors…or better known by their full real name, EnRiching Textual Editorializers!


How Do People Make These Things?!

As with a great deal of really cool tech stuff, they appear deceptively simple and yet took a tremendous amount of work to get to that point. Fortunately, with really cool tech stuff, motivated intelligent people are continuously building off of predecessors and making that which used to be incredibly difficult, a bit less difficult. Enter stage left, Draft.js! It’s a humdinger of a framework for building your own rich text editor in React. Like many other creations by the ever productive Facebook folks, Draft.js was born to solve problems plaguing developers.

In the grand scheme of internet development evolution, I’ve not been in the game that long. One way of seeing a silver lining in this, is that I’m coming into the game with much better tools to work with. I don’t really know the pain of early Javascript developers. But I can imagine and I can be thankful.

For many years, creating your own WYSIWYG (what you see is what you get) rich text editor from scratch would be an enormous undertaking. So instead of reinventing the wheel, there were options like jQuery plugins, CKEditor (which had the original amazing title of FCKeditor), or this thing called ‘Content Editable’ which is an attribute you can give to a <div>. As you type, it adds the text and upon hitting enter, just keeps adding more and more<div>'s separated by break or paragraph tags, depending on the browser being used. There’s a great example of this quirkiness starting at minute 2:11 of this presentation on Draft.js. After watching this, I praised the powers that be for sparing me from having to program like this. Here’s an excerpt from a post on Facebook’s engineering blog about how they were dealing with this issue before creating Draft.js:

In the past, we’ve addressed this format with <textarea> and background highlighter <div> tags. However, this solution led to a poor developer experience, with lots of DOM hacks needed to measure text to autogrow the textarea, keep highlighters positioned properly, and track cursor positions with invisible unicode characters. There were also challenges with synchronizing state and DOM, since the plaintext contained no information about the structured mention data. These issues in turn led to poor user experiences, with misaligned backgrounds and broken input. Not only that, but since <textarea> supports only plaintext, we could never expand our feature set to include richer styles or embedded content.

WOOF.

Let’s Take a Gander at Draft.js Shall We?

The aim of this is to make a high level overview of getting started and assumes basic knowledge of React

If you haven’t already installed create-react-app globally, start with this:

npm install -g create-react-app

Then bootstrap a new React project:

create-react-app draft-js-test

Then cd into that bad boy and install Draft.js:

yarn add draft-js

Make a new file and a container component for the editor:

Tight

At the top of the file is the import for Draft.js with three special nuggets, Editor, EditorState and RichUtils. We’ll just focus on Editor and EditorState to begin with. Editor is the actual React component. Here’s the description for EditorState ripped right from the docs:

The EditorState object is a complete snapshot of the state of the editor, including contents, cursor, and undo/redo history. All changes to content and selection within the editor will create new EditorState objects.

Next two things:

  • create a new EditorState object with EditorState.createEmpty() inside of the component’s state
  • Render the Editor component and pass the EditorState as a prop
Chill

The third step for getting the bare bones text editor (we ain’t rich yet!) is to create the onChange method and pass that as a prop to the Editor component.

VChill

Now any change that happens within the text editor will be executed through the onChange method and update the state with the latest and greatest.

Rich Time!

This is where that RichUtils comes into play. According to the docs, RichUtils :

  • Has information about the core key commands available to web editors, such as Cmd+B (bold), Cmd+I (italic), and so on
  • For inline and block style behavior…the RichUtils module provides a number of useful functions to help manipulate state.

Show time…

Make an handleKeyCommand method like such:

Major Key

This method takes in a command as an argument and calls the built in handleKeyCommand method on RichUtils , passing in the previous EditorState and the command as arguments. If a new updated EditorState does in fact get produced, then pass that newState to the onChange method which will update the overall state.

It’s also important to note those lil return statements. The docs describe their role as thus:

…returning 'handled' instructs the editor that the command has been handled and no more work is required…By returning 'not-handled' in all other cases, default commands are able to fall through to default handler behavior.

This is especially useful in key binding situations, like if you want to smash a CMD+S to save your current work. Here’s the section in the docs that covers this circumstance.

Back on track to getting rich…pass this handleKeyCommand method built above as a prop to the Editor component:

Your key is my command

Now slamming commands like Cmd+B(bold), Cmd+I (italic), and Cmd+U(underline) will start paying off and your text editor can now be considered a rich text editor…or if you (as I certainly) prefer: EnRiched Textual Editorializer!

Let’s Bash Some Buttons

RichUtils is indeed rich with utilities, as one might deduce from the name…let’s see what’s in the box!

We’ll make three buttons, for making bold, italic and underlined. Like so:

The methods we’ve passed to the onClick event of the buttons will look like this:

richy rich

The toggleInlineStyle method takes in the current EditorState object and the selected style. This all gets passed to the onChange method which will update the overall EditorState.

A good thing to note, is that when you click these buttons, they will only update the style of selected text. If you’re just typing with plain text, then click one of these style buttons and then start typing again, there will be no change to the style of the text. I thought I had messed something up at first, but the docs on this part of the API explicitly state that toggleInlineStyle is meant for the given selection.

The whole enchilada of code done so far looks like this:


To Conclude

Draft.js is an awesome framework if you want to dive into creating your own rich text editor. This was just a quick jaunt into the WYSIWYG forest and boy this forest is deep and dense. Years ago, making your own rich text editor was an enormous undertaking. Now with Draft.js and other popular frameworks like Quill and Slate.js, making your own is much more accessible. However doing it well with lots of features and stylings is a considerable amount of work. This should be taken into account when embarking on a project. Even big teams of developers will opt for licensing a rich text editor as opposed to making their own from scratch. For a business, it’s about what’s worth the time and money. For lil ole me, it’s worth is having fun, learning new tools to build things that come to mind.

Jesse Billard

Written by

A blog for chronicling a coding journey

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade