A fast, keyboard-first Markdown editor with a live preview. Write Markdown on one side and watch it render on the other, with the scroll, undo, and keyboard flow all built to stay out of your way.
Built with Vite, React 18, TypeScript and Tailwind CSS 4.
- Live preview, three view modes. Edit, Split, or Preview. In Split the two panes scroll-sync by proportion, so the source and the rendered output stay aligned even when one side runs longer.
- GitHub-flavored Markdown. Tables, task lists, strikethrough and fenced code, rendered through
react-markdownandremark-gfm, with syntax-highlighted code blocks viarehype-highlightandhighlight.js. - Live syntax overlay in the editor. A highlighted layer sits behind a transparent textarea, fading back the raw Markdown markers (
**,#,>) so your formatted text stands out as you type. - Formatting toolbar. Sixteen actions, covering bold, italic, strikethrough, H1 to H3, bullet, numbered and task lists, blockquote, inline code, code block, link, image, table and horizontal rule. Each inserts with the cursor left where you would expect it.
- Keyboard-first. Every action has a shortcut, with an in-app shortcuts panel. Bindings adapt to Mac (⌘ / ⌥) or Windows and Linux (Ctrl / Alt) automatically, and use physical key codes so they hold up on non-US layouts.
- Smart undo and redo. A debounced history folds a run of typing into a single step, while toolbar edits commit immediately. Undo flushes pending input, redo never drops you mid-word, and the stack is capped so memory stays bounded.
- Find in the preview. Case-sensitive search highlights every match in the rendered output and steps through them.
Ctrl / ⌘ + Fpre-fills the box with the current selection. - Editor niceties. Tab inserts two spaces, brackets and quotes auto-close around a selection, and Enter continues a list, incrementing ordered items.
- Persistence and export. Autosaves to the browser and survives a refresh, opens and downloads
.md,.markdownand.txtfiles, and copies clean output to the clipboard. - Light and dark themes that persist across sessions.
- Live word, character and line counts.
npm install
npm run dev # start the Vite dev server
npm run build # production build
npm run preview # preview the production buildThe app is fully client-side, so there is nothing else to configure.
A few notes on the parts that took the most care:
- Real-time rendering. Content flows from source to Markdown AST to HTML on every change, through the
react-markdownpipeline. - Proportional scroll-sync. Split view aligns the panes by viewport ratio rather than raw pixels, so they track each other even when the rendered side is taller. A guard flag prevents feedback loops between the two scroll handlers.
- No-jump editing. Toolbar actions restore the caret and scroll position inside a
useLayoutEffect, before the browser repaints, so the view never jumps when you format text. - Debounced history. Typing is snapshotted on a debounce while toolbar edits commit at once, which keeps undo precise without flooding the stack.
- State. Plain React hooks, no external state library. Content and view mode are mirrored to
localStorage.
- Framework: React 18, TypeScript, Vite
- Styling: Tailwind CSS 4
- Markdown: react-markdown, remark-gfm, rehype-highlight, highlight.js
- Icons: lucide-react
- Hosting: Vercel
Scaffolded from a Figma design with Figma Make, then refined by hand where the interaction details mattered.