
Woof Editor 0.2: Try the Editor That Can't Drift
Three weeks ago we published Barkdown, a codec whose promise is that it does the exact opposite of what the popular package Marked does. Marked parses and converts markdown source into HTML. Barkdown converts HTML back into byte-identical markdown guaranteeing a clean roundtrip. It is heavily tested and enforced by a property suite that throws a couple thousand generated documents at it per run (read more about it here).
A codec is just infrastructure, however. You can't type into it. It has no UI. The thing people actually touch is the editor, and that is what we are releasing properly today.
Woof Editor is an open-source contenteditable markdown editor for Svelte 5. You seed it with markdown, your user edits a rendered WYSIWYG surface, and every mutation serializes back through Barkdown to the canonical markdown form of what is on screen. Version 0.2.0 shipped this weekend, and alongside it a live demo where you can test the central claim yourself: the demo renders the serializer's output next to the editing surface, updating as you type, so you can watch the markdown stay exactly as tidy as it started.
Why another markdown editor?
Because the existing ones eat documents, slowly. Traditional markdown WYSIWYGs render markdown to DOM, let you edit the DOM, then serialize back through a separate code path that was never tested as the inverse of the parser. The output re-parses a little differently than the input did. Nothing crashes; the fences just grow a blank line per save, the list markers churn, the quote style wanders. We wrote about the failure mode at length in the Barkdown post, because we extracted that serializer from our own production CMS after watching it happen to us.
With Barkdown handing the serialization, the editor's job narrows to what an editor should be: menus, a link popover, footnotes, keyboard shortcuts, undo and redo, paste handling.
The editor was originally written for Replicator, our brand and content management platform, where the same surface edits every article we publish, this one included.
What 0.2.0 actually is
The internal changelog title for 0.2.0 is "consumable-anywhere hardening," which is accurate. 0.1.0 proved the editor worked; it also quietly assumed it was running inside Replicator. This release removes those assumptions one at a time:
- Paste sanitization now runs pasted and seeded HTML through DOMPurify, stripping scripts and event handlers, with a
sanitizeprop so consumers can tighten or widen the schema instead of inheriting ours. A bug whereALLOWED_TAGSandALLOWED_ATTRoverrides silently failed is fixed, as is one where a partial schema could accidentally widen the defaults. - Link previews are pluggable. 0.1.0 called a hardcoded
/api/link-previewendpoint that only existed in our app; 0.2.0 takes aloadLinkPreviewfunction and stays out of your routing. - Styling is scoped and themeable: stable class names,
--woof-*custom properties, and aclassprop that lets you pass your site's typography onto the editing body. No more inheriting our look because our classes were baked in. - Keyboard undo and redo (Cmd / Ctrl+Z and friends) work, including within the serialization debounce window, which was the fiddly part.
- Code blocks round-trip correctly in both directions, and the whole thing now has browser test coverage running the component in a real DOM, where before there were only node-side unit tests.
Three of those changes are breaking, which is what the 0.x is for. If you adopted 0.1.0, the migration is small and the changelog spells it out.
Where it is running
Two places at present. Replicator's blog editor is the production origin. Every keystroke on every article in our CMS goes through this pairing of surface and codec, and has for months, well before we published the Barkdown package and before we had the idea of extracting the editor for other projects. The second place that Woof Editor is working today is a customer knowledge base product. That project is itself in beta, and the build that uses woof-editor has not reached production yet, so file this under "second consumer exists" rather than "battle-tested elsewhere." It is the second consumer that forced most of the 0.2.0 changes, which is the usual story: the first external adoption is the audit.
Let's Not Get Ahead of Ourselves
Woof Editor is in beta and versioned accordingly. Minor releases can break the API, and 0.2.0 did, three times. Pin your version.
The peer dependency list is real: svelte ^5.29, marked ^18, marked-footnote ^1.4, @kevinpeckham/barkdown ^0, and isomorphic-dompurify ^2. That is not dependency sprawl, it is the contract being visible. barkdown's guarantee is stated against a specific range of marked, and an editor built on that guarantee should make you choose the parser version rather than hiding it.
And the no-drift claim is enforced, not proven. It rests on barkdown's test fence: fixture corpus, adapter conformance runs, and property suites at roughly 2,000 generated documents per run. We say "tested to invert marked" rather than pretending it is a theorem.
Try it
The demo is here: https://www.woofeditor.dev. It allows you to type, drag blocks around with the gutter chips, add a footnote, and watch the markdown pane. If you can make the serialized output drift from canonical form, we want the bug report.
bun add @kevinpeckham/woof-editor
MIT licensed, on npm with the peer list in the README, and a walkthrough covering the state class, saving, and custom toolbars. The whole consumer API is one component and one state class: seed MarkdownEditorState with markdown, render <MarkdownEditor {editor} />, read editor.markdownCurrent when you save.