DEV Community

Shayan
Shayan

Posted on

Building a Type-Safe Rich Text Editor in Next.js (with Lexical & Lexkit)

So… I’ve always hated building editors. Either they’re too basic or just way too complex.

Then I was like: why not build my own? And that’s how LexKit happened ⚡️

Lexkit Rich Text Editor

It’s a React-first, type-safe, DX-friendly editor system built on top of Lexical.

Perfect for Next.js apps if you want something lightweight but not boring.


Getting Started (Basic Example)

Here’s literally the simplest editor you can make with LexKit:

"use client";

import {
  createEditorSystem,
  boldExtension,
  italicExtension,
  listExtension,
  linkExtension,
  historyExtension,
  RichText,
} from "@lexkit/editor";
import "./basic-editor.css";

// 1. Define your extensions (for features like bold, lists, etc)
const extensions = [
  boldExtension,
  italicExtension,
  listExtension,
  linkExtension,
  historyExtension,
] as const;

// 2. Create typed editor system
const { Provider, useEditor } = createEditorSystem<typeof extensions>();
Enter fullscreen mode Exit fullscreen mode

That’s the “engine.”
Now let’s add a toolbar so you can actually click stuff:

function Toolbar() {
  const { commands, activeStates } = useEditor();

  return (
    <div className="basic-toolbar">
      <button onClick={() => commands.toggleBold()} className={activeStates.bold ? "active" : ""}>
        Bold
      </button>
      <button onClick={() => commands.toggleItalic()} className={activeStates.italic ? "active" : ""}>
        Italic
      </button>
      <button onClick={() => commands.toggleUnorderedList()}>• List</button>
      <button onClick={() => commands.toggleOrderedList()}>1. List</button>
      <button onClick={() => commands.undo()} disabled={!activeStates.canUndo}>Undo</button>
      <button onClick={() => commands.redo()} disabled={!activeStates.canRedo}>Redo</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

And the editor itself:

function Editor() {
  return (
    <div className="basic-editor">
      <Toolbar />
      <RichText
        placeholder="Start writing your content here..."
        classNames={{
          container: "basic-editor-container",
          contentEditable: "basic-content",
          placeholder: "basic-placeholder",
        }}
      />
    </div>
  );
}

export function BasicEditorExample() {
  return (
    <Provider extensions={extensions}>
      <Editor />
    </Provider>
  );
}
Enter fullscreen mode Exit fullscreen mode

Boom 💥 you got a working editor in Next.js with bold, italic, lists, undo/redo.
No crazy config, no vendor lock-in.


Features that just work

  • Type-safe extensions → autocomplete knows what commands exist.
  • Next.js Ready → works out-of-the-box with use client.
  • Theming? yep → the DefaultTemplate plays nice with next-themes
  • Production-ready → images, tables, markdown, html import/export, history, you name it.

Final thoughts

Rich text editors suck less when you can actually understand the code.
LexKit is my attempt to make editors fun (and honestly DX-friendly).

If you’re already playing in the Next.js world → give it a spin.
Docs are here 👉 lexkit.dev


PS: if this helped, smash the ❤️ or drop a comment. Makes me feel less like I’m coding into the void 😂

Lexkit is open source, free and under MIT license. I love to develop it and push it forward. But like every other open source project, it's only possible with your supports. whether it's a github star⭐, a comment or even a small donation.

To support this project check Github Repo
Thanks for your time, try it out and report any issues or bugs.

Top comments (0)