Type Markdown on the left and see the rendered HTML update live on the right. Supports full CommonMark plus GFM extensions: tables, strikethrough, task lists, and autolinks.
A real-time Markdown previewer built with React 19 and Vite. The interface splits the screen into two equal panes — a monospace textarea on the left and a live HTML preview on the right — with the header taking the top 15% of the viewport. Markdown is parsed by react-markdown v10 with the remark-gfm plugin, adding GitHub Flavored Markdown on top of CommonMark: tables with alternating row shading, strikethrough text, interactive task-list checkboxes, and bare URL autolinks. The preview panel styles all standard elements — headings, blockquotes, fenced code blocks, inline code, lists, and horizontal rules — using CSS variables so the theme adapts automatically to the user's light/dark preference.
How It Works
Markdown → HTML Pipeline (remark / rehype) ═════════════════════════════════════════════ Raw Markdown string (textarea value) │ ▼ ┌───────────────┐ │ remark-parse │ text → MDAST (Markdown AST) └───────┬───────┘ Heading, Paragraph, Code, List... │ ▼ ┌───────────────┐ │ remark-gfm │ extend AST with GFM nodes: └───────┬───────┘ Table, Strikethrough, TaskListItem, Autolink │ ▼ ┌───────────────┐ │ remark-rehype │ MDAST → HAST (Hypertext AST) └───────┬───────┘ element{tag, props, children}, text, root │ ▼ ┌───────────────┐ │ rehype-react │ HAST → React elements └───────┬───────┘ │ ▼ Live preview pane — re-renders on every keystroke No raw innerHTML — the remark/rehype pipeline produces React elements, so XSS is not possible.
Split-Pane Layout ══════════════════ ┌────────────────────────────────────────┐ ▲ │ Header │ │ 15vh ├────────────────────┬───────────────────┤ ▼ │ Textarea │ Preview pane │ ▲ │ (monospace) │ (styled HTML) │ │ │ 50% width │ 50% width │ │ 85vh │ overflow-y: auto │ overflow-y: auto│ ▼ └────────────────────┴───────────────────┘ CSS variable scoping bug (fixed): ───────────────────────────────── :root vars defined globally → work in textarea ✓ react-markdown renders into div → vars not inherited ✗ fix: pass vars as inline style on the preview div ✓ Both panes scroll independently. CSS variables had to be explicitly forwarded into the preview container.
In Action
Editor proof points
Split-pane layout keeps Markdown input and rendered preview visible together.
Independent scrolling prevents long documents from shifting the whole page.
Vite and React keep the editor responsive while content updates live.
Split-pane editor with live preview
Markdown rendering proof points
react-markdown handles the AST-to-React render path.
remark-gfm adds tables, task lists, and strikethrough support.
Preview styling is scoped so generated content inherits the intended theme.
GFM table rendering
Dev Notes
Problems Solved
Needed a fast, clean Markdown editor with live preview that supported full GFM — tables, task lists, strikethrough — without building a parser from scratch. The split-pane layout needed to work at any viewport size without layout shift as you type.
Errors & Fixes
react-markdown v10 changed its plugin API from v9 — the rehype plugin chain required explicit configuration to work alongside remark-gfm. CSS variables defined at the root didn't scope into the preview panel's rendered HTML; fixed by re-applying them as inline styles on the preview container.
What I Learned
The remark/rehype plugin ecosystem and how react-markdown processes AST nodes before rendering. Vite's CSS handling quirks, and deploying a React + Vite app to Vercel with correct SPA routing config so direct URL loads don't 404.