Zero dependencies
Nothing in your node_modules to audit, patch, or wait on. The entire package is one small file.
React · Zero dependencies · MIT ·
Feather Editor is a React WYSIWYG field with Markdown round‑trip, in roughly the size of a short paragraph. No dependencies, no build step — the browser does the formatting, and Feather just gets out of the way.
The pitch, in one chart
Most rich-text editors ship tens to hundreds of kilobytes before you write a word. Feather is the sliver on the left you can barely see.
Why it's this small
Feather doesn't reimplement text editing. The browser already knows how — Feather is the thin, careful layer on top.
Nothing in your node_modules to audit, patch, or wait on. The entire package is one small file.
Edit visually, store Markdown; load Markdown, edit visually. A hand-written serializer and loader — no parser library bolted on.
The contenteditable region stays uncontrolled. React reads from the DOM and never re-writes it, so editing feels native.
Drop-in CSS files that override a handful of --fe-* custom properties. Mix and match, swap with a single prop.
No, really — that's all of it
Not a teaser snippet. This is the core that renders the toolbar, handles every formatting command, and exposes a clean React component.
import { useRef } from "react"; const x = (c, v) => document.execCommand(c, false, v); export default function Editor({ value = "", onChange }) { const r = useRef(null); const s = () => onChange?.(r.current.innerHTML); const B = ({ c, v, l }) => ( <button onMouseDown={(e) => (e.preventDefault(), x(c, v), s())}>{l}</button> ); return ( <div className="feather-editor"> <div className="feather-bar"> <B c="bold" l="B" /> <B c="italic" l="I" /> <B c="formatBlock" v="<h2>" l="H2" /> <B c="insertUnorderedList" l="List" /> </div> <div ref={r} className="feather-content" contentEditable suppressContentEditableWarning onInput={s} dangerouslySetInnerHTML={{ __html: value }} /> </div> ); }
Don't believe us? The number above isn't typed in — your browser just fetched
dist/core.esm.js and gzipped it. It's the exact file published to npm:
inspect it on unpkg ↗
or grab the raw file ↗ and gzip it yourself.
Drop it in
One package, two entry points. Use the full editor when you want Markdown round-trip, or the core build when every byte counts.
# install
npm i feather-editor
Markdown in, Markdown out. Hand-written round-trip, no parser library.
import Editor from "feather-editor"; import "feather-editor/themes/light.css"; function Notes() { const [md, setMd] = useState("# Hello\n\nStart **writing**."); return <Editor markdown={md} onChange={setMd} />; }
HTML in, HTML out. The bare editor — bring your own serializer if you need one.
import Editor from "feather-editor/core"; import "feather-editor/themes/light.css"; function Notes() { const [html, setHtml] = useState("<p>Hello</p>"); return <Editor value={html} onChange={setHtml} />; }
25 ways to dress it
Each theme is a small CSS file that sets a handful of --fe-* custom properties. Import the ones you want, switch with a single prop — or roll your own in under a minute.
A quiet classic — see the link.
Easy on the eyes — focus on the link.
Warm pages, steady ink, a tidy margin.
A deep sky, one bright star.
A still grove, one bright path.
A cool tide, a far shore.
A soft letter, a folded card.
A clean margin and one quiet link.
A honeyed afternoon, a thin thread.
A gentle hush, a single page.
A fresh leaf, a bright green stem.
A quiet draft, one steady line.
A plain draft, one careful edit.
A warm hour, a long red line.
A measured draft, one tidy link.
A balanced palette, an even line.
A calm chord, a blue cursor.
A bold draft, a purple link.
A sharp sentence, one black line.
A warm mug, a folded napkin.
A green draft, a soft trim.
A cool field, one bright signal.
A dry wind, a clear line.
A rich draft, one bright seam.
A deep well, one cold spark.
Import the theme CSS, then pass the name as a prop: import "feather-editor/themes/dracula.css" and <Editor theme="dracula" />.
The honest part
Feather is deliberately small, which means it's deliberately limited. If you need collaborative editing, tables, a structured document model, or bulletproof Markdown parsing for untrusted input, reach for ProseMirror, Tiptap, or Lexical — and budget the kilobytes. Feather is for the common case: a clean, formatted text field that won't bloat your bundle. If that's what you need, nothing else comes close on size.