What Is WYSIWYG and How Do You Build a WYSIWYG Editor?

Updated

WYSIWYG stands for "what you see is what you get": the editing surface shows content already formatted, so bold text looks bold and headings look like headings while you type, rather than exposing markup. You build one by combining three parts — an editable surface, a formatting UI, and rules that convert typed or pasted input into structured content. In React, Plate (built on Slate) supplies these as plugins and components, so you assemble behavior instead of writing a document model from scratch.

WYSIWYG vs. Markdown vs. raw HTML

The difference is where formatting lives and when it is applied.

Approach What the author edits Formatting applied Typical trade-off
WYSIWYG Rendered text Live, as you type or via toolbar Direct manipulation; needs a document model and selection handling
Markdown Plain text with syntax (**bold**) On preview or render Fast to write, portable, but not "what you see" while editing
Raw HTML Tags and attributes On render in a browser Full control, high error surface, poor for non-technical authors

A WYSIWYG editor is not just a styled textarea. It maintains a structured document (nodes, marks, and selections) and re-renders that structure on every change. That structure is what lets you apply bold to a selection, split a paragraph on Enter, or turn # into a heading.

The core building blocks

Any WYSIWYG editor, regardless of library, needs these pieces:

  • Editable surface — a focusable, contenteditable-like region that owns the cursor and selection.
  • Document model — a tree of blocks (paragraphs, headings, lists) and inline marks (bold, italic, links).
  • Formatting UI — a toolbar, floating menu, or keyboard shortcuts that mutate the model at the current selection.
  • Input rules — patterns that transform typed text into structure, such as # becoming a heading or - becoming a list item.
  • Serialization — converting the model to and from HTML, JSON, or Markdown for storage and paste.

If any of these is missing, the editor either can't represent formatting, can't apply it, or can't save it.

How Plate and Slate provide WYSIWYG behavior in React

Slate is the underlying framework: it defines the document model, selection, and transformation operations, and leaves rendering to you. Plate sits on top as a plugin and component system, so common WYSIWYG features arrive as installable pieces rather than hand-written logic.

Plate's own framing is a "set of beautifully-designed, customizable plugins and components to help you build your rich-text editor," and its page lists Framework · Plugins · Components alongside Plugin Input Rules — the mechanism behind typed shortcuts like turning a line into a heading. The stack is React-based and integrates with Tailwind CSS, Radix UI, and shadcn/ui, and it works in Next.js projects.

The practical consequence: you get an editable surface and a plugin pipeline, then add only the behaviors you need. Input rules, for example, are a plugin concern, so you configure which patterns trigger which block types instead of writing a keydown parser.

A minimal setup path

Plate's documented starting point is the shadcn-style CLI, which adds a preconfigured editor to your project:

npx shadcn@latest add @plate/editor-ai

The page also shows an AI editor preview with Open in New Tab and Refresh Preview controls, so you can inspect a working editor before wiring your own. After the component is added, the general workflow is:

  1. Render the editor component in a React page. Expected result: a focusable surface where you can type.
  2. Add plugins for the features you want (formatting, input rules, lists). Expected result: toolbar actions and typed shortcuts change the document.
  3. Connect serialization to your storage format. Expected result: content survives a save and reload.
  4. Verify by typing a heading shortcut, applying bold to a selection, pasting from another app, and reloading the page.

Common pitfalls

  • Paste handling. Pasting from a browser or word processor brings foreign HTML. Without a normalization step, you get nested spans and inline styles that break your model. Decide up front whether to sanitize, strip, or map pasted content to your own blocks.
  • Selection state. The cursor and selection live outside React's normal render cycle in contenteditable-based editors. Toolbar buttons that read stale selection will format the wrong range; capture and restore selection around UI interactions.
  • Serialization mismatch. If your stored format and your editor model disagree, round-tripping loses marks or merges blocks. Test save → reload → edit, not just save.
  • Input rule conflicts. Overlapping patterns (for example, * for both bold and a bullet) produce surprising transforms. Order and scope your rules deliberately.
  • Uncontrolled re-renders. Re-rendering the editor from external state on every keystroke can reset the cursor. Keep the document model as the source of truth during editing.

When this approach fits

Choose a plugin-based React editor like Plate when you are already in React, want control over the document model, and need WYSIWYG editing with custom blocks. Choose Markdown when portability and plain-text diffs matter more than live formatting. Choose a batteries-included editor when you want a finished product rather than a framework to assemble — the trade-off is less control over the model and UI.