Build a React Text Editor Component 

A few months ago, I was working on a React project for a client in New York who needed a custom text editor for internal documentation. They wanted something that felt like Google Docs, clean, fast, and with formatting options like bold, italic, and bullet lists.

At first glance, it seemed like a simple task. But once I started exploring, I realized there were several great ways to build a React text editor component, each with its own strengths.

In this tutorial, I’ll walk you through two methods I’ve personally used to create a text editor in React, one using Lexical (by Meta) and another using CKEditor 5. Both are powerful, modern solutions, and I’ll share complete working examples for each so you can easily integrate them into your own projects.

What Is a React Text Editor Component?

A text editor component in React allows users to create and format text directly inside your web app. It’s commonly used in dashboards, CMS systems, blogs, and note‑taking tools.

Unlike a simple <textarea>, a rich text editor supports formatting like bold, italic, underline, lists, links, and images, all while maintaining data consistency through React’s state management.

Method 1 – Build a React Text Editor Using Lexical

Lexical is a lightweight, extensible text editor framework developed by Meta (Facebook). It’s highly modular and gives you full control over formatting, keyboard shortcuts, and plugins.

When I first used Lexical, I was impressed by how fast and customizable it was compared to older editors like Draft.js.

Step 1 – Install Lexical

Open your terminal and run:

npm install lexical @lexical/react

This installs the Lexical core and its React bindings.

Step 2 – Create the Editor Component

Here’s the complete code for a simple Lexical text editor:

// File: LexicalEditor.js
import React from "react";
import { LexicalComposer } from "@lexical/react/LexicalComposer";
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";

function EditorChangeHandler() {
  const [editor] = useLexicalComposerContext();

  React.useEffect(() => {
    return editor.registerUpdateListener(({ editorState }) => {
      editorState.read(() => {
        const textContent = editor.getEditorState().toJSON();
        console.log("Editor content:", textContent);
      });
    });
  }, [editor]);

  return null;
}

export default function LexicalEditor() {
  const config = {
    namespace: "MyEditor",
    theme: {
      paragraph: "editor-paragraph",
    },
    onError(error) {
      console.error(error);
    },
  };

  return (
    <LexicalComposer initialConfig={config}>
      <RichTextPlugin
        contentEditable={<ContentEditable className="editor-input" />}
        placeholder={<div className="editor-placeholder">Start typing...</div>}
      />
      <HistoryPlugin />
      <OnChangePlugin onChange={(editorState) => console.log(editorState)} />
      <EditorChangeHandler />
    </LexicalComposer>
  );
}

Step 3 – Add Some Basic Styles

/* File: LexicalEditor.css */
.editor-input {
  min-height: 200px;
  border: 1px solid #ccc;
  padding: 10px;
  border-radius: 6px;
  font-size: 16px;
  outline: none;
}

.editor-placeholder {
  color: #aaa;
  position: absolute;
  pointer-events: none;
}

Step 4 – Use It in Your App

// File: App.js
import React from "react";
import LexicalEditor from "./LexicalEditor";
import "./LexicalEditor.css";

function App() {
  return (
    <div style={{ width: "70%", margin: "40px auto" }}>
      <h2>React Text Editor with Lexical</h2>
      <LexicalEditor />
    </div>
  );
}

export default App;

You can see the output in the screenshot below.

React Text Editor Component 

This setup creates a fully functional text editor that supports basic formatting and undo/redo history. The OnChangePlugin listens for changes, allowing you to save or sync content in real time.

Lexical is ideal when you need a lightweight, customizable editor that doesn’t rely on heavy dependencies.

Method 2 – Use CKEditor 5 with React

When clients need a more feature‑rich editor with built‑in toolbar options, image uploads, and collaboration tools, I often go with CKEditor 5.

It’s a battle‑tested WYSIWYG editor with an official React integration, making it easy to use with minimal setup.

Step 1 – Install CKEditor

Run the following command:

npm install @ckeditor/ckeditor5-react @ckeditor/ckeditor5-build-classic

Step 2 – Create the Editor Component

Here’s the complete working code:

// File: CKEditorComponent.js
import React, { useState } from "react";
import { CKEditor } from "@ckeditor/ckeditor5-react";
import ClassicEditor from "@ckeditor/ckeditor5-build-classic";

export default function CKEditorComponent() {
  const [content, setContent] = useState("");

  return (
    <div style={{ width: "70%", margin: "40px auto" }}>
      <h2>React Text Editor with CKEditor 5</h2>
      <CKEditor
        editor={ClassicEditor}
        data="<p>Hello from CKEditor 5!</p>"
        onReady={(editor) => {
          console.log("Editor is ready to use!", editor);
        }}
        onChange={(event, editor) => {
          const data = editor.getData();
          setContent(data);
        }}
      />
      <h4>Editor Output:</h4>
      <div
        style={{
          background: "#f9f9f9",
          border: "1px solid #ddd",
          padding: "10px",
          borderRadius: "6px",
        }}
        dangerouslySetInnerHTML={{ __html: content }}
      />
    </div>
  );
}

This code creates a classic CKEditor instance inside a React component. The onChange event keeps track of the content in real time, which you can save to a database or display elsewhere in your app.

Step 3 – Add Toolbar Customization (Optional)

You can customize the toolbar of CKEditor to include only the tools you need.

const editorConfiguration = {
  toolbar: ["bold", "italic", "link", "bulletedList", "numberedList", "undo", "redo"],
};

Then, pass it as a prop:

<CKEditor
  editor={ClassicEditor}
  config={editorConfiguration}
  data="<p>Start writing...</p>"
  onChange={(event, editor) => setContent(editor.getData())}
/>

You can see the output in the screenshot below.

Build a React Text Editor Component 

This gives users a clean, focused editing experience.

Method 3 – Build a Minimal Text Editor with contentEditable

If you don’t want to rely on third‑party libraries, you can build a minimal custom editor using plain React and the contentEditable attribute.

Here’s a simple example I often use for prototypes:

// File: SimpleEditor.js
import React, { useState } from "react";

export default function SimpleEditor() {
  const [content, setContent] = useState("Type something here...");

  return (
    <div style={{ width: "70%", margin: "40px auto" }}>
      <h2>Simple React Text Editor</h2>
      <div
        contentEditable
        suppressContentEditableWarning
        style={{
          border: "1px solid #ccc",
          padding: "10px",
          minHeight: "150px",
          borderRadius: "6px",
        }}
        onInput={(e) => setContent(e.currentTarget.innerHTML)}
        dangerouslySetInnerHTML={{ __html: content }}
      />
      <h4>Editor Output:</h4>
      <div
        style={{
          background: "#f0f0f0",
          padding: "10px",
          borderRadius: "6px",
        }}
        dangerouslySetInnerHTML={{ __html: content }}
      />
    </div>
  );
}

This approach uses native browser capabilities. It’s lightweight and great for quick demos, but it lacks advanced formatting controls and consistent cross‑browser behavior.

Choosing the Right Method

MethodBest ForKey Features
LexicalDevelopers who want flexibility and performanceModern, modular, lightweight
CKEditor 5Teams that need a full‑featured editorToolbar, image upload, and collaboration
contentEditableQuick prototypes or minimal appsSimple and dependency‑free

From experience, I usually start with Lexical for internal tools and CKEditor for production‑grade web apps.

Bonus Tip – Saving Editor Data

No matter which method you choose, you’ll likely need to save the editor’s content to a server or local storage.

Here’s a quick example using localStorage:

useEffect(() => {
  localStorage.setItem("editorContent", content);
}, [content]);

This ensures your users never lose their work if they refresh the page.

Building a React text editor component can seem intimidating at first, but once you understand the available tools, it’s actually quite straightforward.

Lexical gives you a developer‑friendly, modular foundation, while CKEditor offers a polished, enterprise‑ready experience. And if you just need something lightweight, React’s native contentEditable can do the job.

You may also read:

Leave a Comment

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.