How would you build a rich text editor (like Medium) in React?
Design a minimal Medium-style rich text editor with contentEditable, commands, history, block/inline formats, selection APIs, and plugins.
Advertisement
đź§© Scenario
You want to create a lightweight Medium-like editor that supports:
- Bold / Italic / Underline / Code formatting
- Headings, paragraphs, quotes
- Inline links
- Undo / Redo
- Keyboard shortcuts (Cmd+B, Cmd+I)
- Persisting content
This must work without external heavy libraries.
đź§ Answer (Design Overview)
1. Approach Options
A. contentEditable-based editor
- Easiest to start
- Browser handles selection
- Use commands + manual formatting
B. Custom editor engine (Slate/Lexical/ProseMirror)
- More stable for complex editors
- Schema-based content
- Better for collaboration, comments, plugins
For this scenario, we focus on contentEditable.
2. Core Architecture
State Representation
Use HTML or JSON:
{
type: 'doc',
blocks: [
{ type: 'paragraph', children: [{ text: 'Hello' }] }
]
}
Selection Handling
Use window.getSelection() to get ranges and apply commands.
Formatting Commands
Use document.execCommand() (deprecated but widely supported) or apply manual format wrapping using Range API.
Undo / Redo
Keep history:
history = [html1, html2, html3];
index = current;
🎮 Live Demo: Rich Text Editor (Medium-style)
🔍 Real-World Tips
- Use Normalization to ensure consistent HTML output.
- Use keyboard handlers for shortcuts.
- Add paste sanitization to clean HTML.
- For serious editors, move to Lexical or Slate for plugin systems.
- For collaboration (Google Docs style), use CRDTs (Yjs, Automerge).
Quick Practice
- Add support for headings using custom commands.
- Implement inline link creation.
- Add paste sanitization.
- Add markdown shortcuts (typing
##becomes<h2>).
Summary
- contentEditable is the easiest way to build a minimal editor.
- Keep HTML or JSON as the canonical state.
- Implement formatting with execCommand or Range API.
- Use history stacks for undo/redo.
Should I use contentEditable or a custom editor engine?
contentEditable is great for simple editors. For advanced features (collaboration, plugins, schema), use Slate/ProseMirror/Lexical.
How do you handle undo/redo?
Track snapshots of document state or use command-based history stacks.
Advertisement
Stay Updated
Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.
Advertisement