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
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; }'
}}
/>
</>
);
}
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';
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>
</>
);
}
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
- https://www.geeksforgeeks.org/difference-between-rich-text-and-plain-text/
- https://dmitripavlutin.com/react-useref/
- https://softwareengineering.stackexchange.com/questions/395128/why-must-api-keys-be-kept-private#:~:text=Why%3F,if%20they%20steal%20your%20credentials.
- https://www.npmjs.com/package/html-react-parser
Top comments (1)
Thank you