React · Zero dependencies · MIT · npm version

The 400‑byte rich‑text editor.

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.

Star on GitHub

Edit this.

  • This is the actual Feather Editor — the same few hundred bytes you'd ship. Select some text and try the toolbar, or type your own words here.
  • It outputs clean HTML
  • …and round-trips to Markdown
  • …without fighting your cursor
436 B gzipped. The whole editor.
measured live from the real file ↗

The pitch, in one chart

Smaller than the alternatives. By a lot.

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.

Feather
≈ 0.4 KB
Kria Lite
≈ 6 KB
Quill
≈ 43 KB
TinyMCE
≈ 250 KB
CKEditor 5
≈ 300 KB

Approximate gzipped sizes; exact numbers vary by configuration and which plugins you include. Feather's figure is measured live above — the core is ≈ 0.4 KB, and ≈ 1.2 KB with the full Markdown round-trip.

Why it's this small

It leans on the platform.

Feather doesn't reimplement text editing. The browser already knows how — Feather is the thin, careful layer on top.

01

Zero dependencies

Nothing in your node_modules to audit, patch, or wait on. The entire package is one small file.

02

Markdown round-trip

Edit visually, store Markdown; load Markdown, edit visually. A hand-written serializer and loader — no parser library bolted on.

03

The caret never jumps

The contenteditable region stays uncontrolled. React reads from the DOM and never re-writes it, so editing feels native.

04

25 themes, one variable contract

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

The whole editor.

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>
  );
}
Core, gzipped≈ 436 B
With Markdown round-trip≈ 1.2 KB
Dependencies0
Build stepNone

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

Two modes. Pick the weight.

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 mode ≈ 1.2 KB gzip

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} />;
}
Core mode 400 B ≈ 0.44 KB gzip

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

A theme for every mood.

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.

BIH2
A clean page.

A quiet classic — see the link.

lightdefault
BIH2
After hours.

Easy on the eyes — focus on the link.

darkneutral
BIH2
Old book.

Warm pages, steady ink, a tidy margin.

sepiawarm paper
BIH2
Past midnight.

A deep sky, one bright star.

midnightdeep navy
BIH2
Among the pines.

A still grove, one bright path.

forestdark green
BIH2
Open water.

A cool tide, a far shore.

oceandeep blue
BIH2
A small note.

A soft letter, a folded card.

rosesoft pink
BIH2
Notebook.

A clean margin and one quiet link.

slatecool gray
BIH2
Warm light.

A honeyed afternoon, a thin thread.

amberwarm amber
BIH2
Soft hours.

A gentle hush, a single page.

lavenderpurple
BIH2
Garden notes.

A fresh leaf, a bright green stem.

mintlight mint
BIH2
Studio at night.

A quiet draft, one steady line.

charcoaldeep gray
BIH2
A fresh sheet.

A plain draft, one careful edit.

paperoff-white
BIH2
Last light.

A warm hour, a long red line.

sunsetwarm orange
BIH2
Calm by default.

A measured draft, one tidy link.

nordicmuted blue
BIH2
Long sessions.

A balanced palette, an even line.

solarized-lightclassic
BIH2
Late terminal.

A calm chord, a blue cursor.

solarized-darkclassic
BIH2
After dark.

A bold draft, a purple link.

draculavibrant
BIH2
Ink on paper.

A sharp sentence, one black line.

monohigh contrast
BIH2
Slow morning.

A warm mug, a folded napkin.

coffeebrown tones
BIH2
Slow garden.

A green draft, a soft trim.

sagesage green
BIH2
Wired in.

A cool field, one bright signal.

cobaltdeep cobalt
BIH2
Long shore.

A dry wind, a clear line.

sandsandy beige
BIH2
Late hour.

A rich draft, one bright seam.

plumdeep plum
BIH2
Off the grid.

A deep well, one cold spark.

abyssnear-black

Import the theme CSS, then pass the name as a prop: import "feather-editor/themes/dracula.css" and <Editor theme="dracula" />.

The honest part

Use the right tool.

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.