silkdown Svelte Themes

Silkdown

Typora and Obsidian style live-preview Markdown editing for CodeMirror 6. Markers reveal on the active line, document stays plain Markdown

Silkdown

Typora and Obsidian style live-preview Markdown editing for CodeMirror 6.

Markers (**, *, `, #, >, …) hide when your cursor leaves the line and reappear when it returns. Headings, lists, links, blockquotes, and fenced code highlight in place. The document on disk is still plain Markdown.

silkdown.dev · docs · examples


Why Silkdown

Most React Markdown editors (Milkdown, Tiptap, MDXEditor) are built on ProseMirror. They store your document as an AST — when you type **bold**, the asterisks are consumed and gone. There is nothing to "reveal" when the cursor returns.

CodeMirror 6 takes the opposite approach: the document is the source string, and decorations sit on top of it. That makes "show markers when the cursor is on this line" a natural fit instead of an architectural fight.

Silkdown is the smallest set of extensions needed to get that experience, packaged so you can drop it into a React, Vue, Svelte, vanilla JS, or Electron app. The core is framework-agnostic; the React adapter is a thin wrapper.

Packages

Package Version Description
@silkdown/core Framework-agnostic CodeMirror 6 extension. The silkdown() factory.
@silkdown/react React wrapper. One controlled component plus an imperative ref.

Quickstart — React

pnpm add @silkdown/react @silkdown/core react react-dom \
  @codemirror/state @codemirror/view
import { useState } from "react";
import { SilkdownEditor } from "@silkdown/react";
import "@silkdown/core/theme.css";

export function Editor() {
  const [value, setValue] = useState("# Hello\n\n**world**");
  return <SilkdownEditor value={value} onChange={setValue} />;
}

The component is controlled. value changes are diffed into the editor without recreating it, so cursor position, selection, and undo history survive across re-renders.

Quickstart — vanilla CodeMirror

import { EditorState } from "@codemirror/state";
import { EditorView, basicSetup } from "codemirror";
import { silkdown } from "@silkdown/core";
import "@silkdown/core/theme.css";

new EditorView({
  state: EditorState.create({
    doc: "# Hello\n\nWorld with **bold** text.",
    extensions: [basicSetup, silkdown()],
  }),
  parent: document.querySelector("#editor")!,
});

silkdown() does not include basicSetup — compose it yourself so you choose whether to enable line numbers, gutters, bracket matching, and the rest. CodeMirror and Lezer packages are peer dependencies; bundling two copies silently breaks decorations.

What's in the box

  • Live-preview reveal of inline marks: bold, italic, strikethrough, inline code.
  • ATX headings (1–6) with per-level styling.
  • Bullet, ordered, and task lists. Task checkboxes are interactive.
  • Links and images, filtered through a default safe-URL policy (http://, https://, data:image/*, relative paths). javascript: and friends are blocked.
  • Blockquotes with a left rule.
  • Horizontal rules rendered as <hr>.
  • Fenced code highlighted in place via @codemirror/lang-markdown's codeLanguages.
  • Keymap: Mod-B, Mod-I, Mod-` to toggle inline marks. Enter continues list markers.
  • GFM enabled (strikethrough, task lists).

What's intentionally out of scope

  • Block reordering, drag handles, slash menus. Those need an AST-based document model. Use ProseMirror or Lexical for that.
  • Tables rendered as widgets. Tables parse correctly but display as plain Markdown source. A table widget is a future possibility, not v1 scope.
  • Schema enforcement. CodeMirror's document is a string; "no headings inside code blocks" is not a thing this editor enforces.

Project status

Pre-1.0 (0.x). The public API is small and approaching stable, but minor versions may still introduce breaking changes. Track them via the changelog and changesets.

The architecture (decoration pipeline, peer-dep boundaries, atomic-range cursor motion) is settled — see docs/architecture.md. The known footgun list when extending Silkdown lives in docs/gotchas.md.

Documentation

The full docs and a live playground live at silkdown.dev:

  • Docs — guides, recipes, and the full API reference.
  • Examples — runnable demos for React, vanilla CodeMirror, custom themes, and extension points.

In-repo references for working on the source:

  • Core API — keymap, CSS theme variables, options, urlPolicy, fenced-code config.
  • React API — props, the imperative SilkdownHandle, SSR notes.
  • Architecture — how decorations, the syntax tree, and atomicRanges cooperate to drive Live Preview.
  • Gotchas — peer-dep identity, decoration ordering, IME composition, block widgets, mobile, large documents, frontmatter, wikilinks.

Development

corepack enable
corepack [email protected] install

pnpm dev          # demo at http://localhost:5173
pnpm test         # unit + integration across packages
pnpm test:e2e     # Playwright suite
pnpm verify       # typecheck + lint + format + tests + build + size budget

Node 22+ is required.

Contributing

Pull requests are welcome. Read CONTRIBUTING.md first — it covers the development loop, the public-API gate (any change to packages/*/src/index.ts must be mirrored in packages/api-snapshot/src/consumer.ts), and the changeset workflow.

By contributing you agree to abide by the Code of Conduct.

Security

Please do not open public issues for security findings. See SECURITY.md for the disclosure process.

Acknowledgements

Silkdown stands on a lot of prior art:

  • CodeMirror 6 — the editor core.
  • @lezer/markdown — the incremental Markdown parser.
  • codemirror-rich-markdoc — closest existing implementation; a useful reference.
  • HyperMD — the original CM5-era live-preview editor; many rendering decisions here echo it.
  • Obsidian and Typora — for proving this UX matters.

License

MIT © Martin Garcia

Top categories

Loading Svelte Themes