DEV Community

Jose Aguilar
Jose Aguilar

Posted on

Creating a Rich Text Editor with TinyMCE and React

Have you ever tried to build out a form that contains a field that requires a lot of text? For example a short bio for a user profile, or a cover letter field for a resume submission. You may want the text to be able to be styled and formatted as the user sees fit; multiple lines, paragraphs, perhaps even bullet points.

The first thing you'll notice is that, while you can format your text within the text field with multiple lines and paragraphs, the text is not rendered back in the same way it was formatted. The text is all together in a single line/paragraph.

Frustrating, isn't it? The reason for this is that when you submit text from a text area component, it is rendered in the DOM as a plain text element. In order to preserve formatting, we need a submit as rich text, and in order to do that we need a Rich Text Editor.

Luckily, implementing a basic text editor in your React application is a fairly straightforward process. In this article I will show you how to implement a rich text editor using TinyMCE.

This article assumes you've created your React app via create-react-app

Create a free TinyMCE account and receive an API key

Signup for a free TinyMCE account here.

In order to use TinyMCE, you'll need an API key. Once you've signed up for an account, your API key will be displayed in your dashboard.

Concealing your API key

If you're not familiar with how to conceal an API key, dotenv is the easiest and most popular solution. Follow the steps below:

  • Install dotenv via npm:
    npm install dotenv --save

  • At the root of your app, create a file called .env

  • Inside .env, save your API key in the following format:
    REACT_APP_TINYMCE_API = <Your API key>

  • Go to your .gitignore file and insert the path to your .env file at the bottom. For example:

# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

#api
.env
Enter fullscreen mode Exit fullscreen mode

Install and set up TinyMCE in your React project

In your React project install TinyMCE with the following command:
npm install --save @tinymce/tinymce-react

Once that's done, you'll need to set up your actual text editor component. In your src folder, create a file called TextEditor.js and insert the following code:

import { useRef } from "react";
import { Editor } from "@tinymce/tinymce-react"

export default function TextEditor() {
    const TINY_MCE_API_KEY = process.env.REACT_APPS_TINY_MCE_API
    const editorRef = useRef(null);

    function log() {
        const content = editorRef.current.getContent();
        console.log(content)
    }

    return (
      <>
        <Editor
          apiKey={TINY_MCE_API_KEY}
          onInit={(evt, editor) => editorRef.current = editor}
          initialValue="<p>This is the initial content...</p>"
          onEditorChange={log}
          init={{
            height: 300,
            menubar: false,
            plugins: [
              'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview',
              'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',
              'insertdatetime', 'media', 'table', 'code', 'help', 'wordcount'
            ],
            toolbar: 'undo redo | blocks | ' +
              'bold italic forecolor | alignleft aligncenter ' +
              'alignright alignjustify | bullist numlist outdent indent | ' +
              'removeformat | help',
            content_style: 'body { font-family:Roboto,Helvetica,Arial,sans-serif; font-size:16px; line-height: 1; }'
          }}
        />
      </>
    );
  }

Enter fullscreen mode Exit fullscreen mode

As you can see in the example code, the API key is accessed via process.env.REACT_APPS_TINYMCE_API. The content of the editor is being saved via the useRef() hook. We also have a function log() that will log the contents of the editor into the console via the onEditorChange prop.

Open up your console and start typing in the editor to see it in action:

As you may have already noticed, it's not just the text that's being logged into the console, but the corresponding HTML tags as well. This is important, as this will help us render the text properly in the end.

Rendering the editor content using html-react-parser

If we try to render the content as is, this is what we'll see:

Remember, even though the proper HTML tags are included. It's still just a regular string, so <p>hello world</p> is really "<p>hello world</p>".

In order to properly display this content, we need to convert our HTML string into one or more React elements. There are several tools for this, but my personal favorite is html-react-parser for its ease of use.

Install html-react-parser

npm install html-react-parser --save

Import the module

import parse from 'html-react-parser';
Enter fullscreen mode Exit fullscreen mode

After that, it's just a matter of using the parse() function and passing an HTML string as an argument, for example parse('<h1>single</h1>'); or parse('<li>Item 1</li><li>Item 2</li>');. In this case, we want to pass the content of the editor as the argument.

Let's refactor our code a little to better see it in action.

import { useRef, useState } from "react";
import { Editor } from "@tinymce/tinymce-react"
import parse from 'html-react-parser';


export default function TextEditor() {
    const TINY_MCE_API_KEY = process.env.REACT_APPS_TINY_MCE_API
    const editorRef = useRef(null);
    const [textContent, setTextContent] = useState('')

    function log() {
        let content = editorRef.current.getContent();
        setTextContent(content)
    }

return (
      <>
        ...Editor component

        <button onClick={log}>Render Text</button>
        <br/>
        <div>
            {parse(textContent)}
        </div>
      </>
    );
  }
Enter fullscreen mode Exit fullscreen mode

Now, we should be able to add rich text and have our styling and formatting preserved. Let's try copy/pasting some randomly generated text:

Much better!

Resources

Top comments (1)

Collapse
 
novo_dev profile image
Lucas Manuel

Thank you