milkdown
Plugin-driven, WYSIWYG Markdown editor for React with a clean prose editing experience.
milkdown
ReactPlugin-driven, WYSIWYG Markdown editor for React with a clean prose editing experience.
Fit
Bundle (gzip)
92.1 kB
307.7 kB raw
Install size includes transitive dependencies. Bundle size is gzipped browser payload.
Freshness
The Problem
Adding a rich text editor to a React app that outputs clean Markdown is surprisingly difficult:
- Most WYSIWYG editors (Quill, TinyMCE, Draft.js) output HTML — not Markdown
- Markdown-outputting editors often look plain or require a lot of custom styling
- Building a custom editor from scratch with ProseMirror is complex and time-consuming
- Many editors are abandoned or have poor TypeScript support
What It Does
Milkdown is a plugin-driven Markdown WYSIWYG editor built on top of ProseMirror and Remark. You write in a live-preview prose environment and the output is always clean Markdown. The plugin architecture means you can add tables, math formulas, slash commands, collaborative editing, and more — only loading what you need.
Installation
npm install @milkdown/core @milkdown/react @milkdown/preset-commonmark @milkdown/theme-nordUsage Example
Basic editor in React
import { Editor, rootCtx, defaultValueCtx } from "@milkdown/core";
import { nord } from "@milkdown/theme-nord";
import { ReactEditor, useEditor } from "@milkdown/react";
import { commonmark } from "@milkdown/preset-commonmark";
import "@milkdown/theme-nord/style.css";
export function MarkdownEditor() {
const { get } = useEditor((root) =>
Editor.make()
.config((ctx) => {
ctx.set(rootCtx, root);
ctx.set(defaultValueCtx, "# Hello Milkdown\n\nStart typing here...");
})
.use(nord)
.use(commonmark)
);
return <ReactEditor editor={get()} />;
}Reading the Markdown output
import { getMarkdown } from "@milkdown/utils";
function SaveButton({ editorRef }) {
function handleSave() {
const markdown = editorRef.get()?.action(getMarkdown());
console.log(markdown); // clean Markdown string
// save to your database
}
return <button onClick={handleSave}>Save</button>;
}Adding table support
import { gfm } from "@milkdown/preset-gfm";
Editor.make()
.config(...)
.use(nord)
.use(commonmark)
.use(gfm) // adds tables, strikethrough, task lists
.create();Related packages
Fast, composable command palette for React — keyboard-driven search UI with fuzzy filtering and accessible markup out of the box.
@dnd-kit/coreReactModern, accessible drag-and-drop toolkit for React — fully customizable with keyboard support, collision detection, and zero dependencies.
embla-carousel-reactReactLightweight, extensible carousel library for React — smooth scrolling, touch/mouse drag, and full CSS control without prescribing markup.
flagsReactProvider-agnostic feature flags SDK for Next.js and React — toggle features without redeploying.
framer-motionReactProduction-ready declarative animation library for React — gestures, layout animations, and scroll-driven effects with a clean API.