# Kagami: Typora-style live Markdown editing on ProseMirror

**URL:** <https://discuss.prosemirror.net/t/kagami-typora-style-live-markdown-editing-on-prosemirror/9126>\
**Category:** Show\
**Created:** [November 4, 2026, 2:44pm UTC](https://discuss.prosemirror.net/t/kagami-typora-style-live-markdown-editing-on-prosemirror/9126 "2026-11-04T14:44:19Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![kkshinkai](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kkshinkai/32/3401_2.png) [@kkshinkai](https://discuss.prosemirror.net/u/kkshinkai)\
**Post date:** [November 4, 2026, 2:44pm UTC](https://discuss.prosemirror.net/t/kagami-typora-style-live-markdown-editing-on-prosemirror/9126/1 "2026-11-04T14:44:19Z")

</div>

Hello everyone,

I’ve been building a Markdown editor component on top of ProseMirror for a while. The first version is now public (MPL-2.0), though it’s still very early, so I thought I’d share it here.

Repo: [https://github.com/kkshinkai/kagami-md](https://github.com/kkshinkai/kagami-md)

Playground: [https://kkshinkai.github.io/kagami-md/](https://kkshinkai.github.io/kagami-md/)

The basic idea is Typora-style editing. You see the formatted document, and the Markdown syntax shows up when your cursor moves into it, then folds away again when you leave.

 ![Syntax expands when the cursor is inside it, and collapses when you leave.](https://discuss.prosemirror.net/uploads/secondsite/original/2X/e/ea608943d726984e26b221b13ff8ee48b98844f2.jpeg)

You can also drag blocks around, Notion-style. I spent a lot of time getting this to behave with nested structure, so when you drag into or out of lists and quotes, the block should land where the drop indicator says it will.

 ![Dragging a block into a nested list.](https://discuss.prosemirror.net/uploads/secondsite/original/2X/a/a2a50928c92187fdb32d87af80f4db4e6144f6eb.jpeg)

The other thing I cared a lot about is the Markdown itself:

- Parsing follows CommonMark closely. Under the hood it uses a modified micromark.
- Markdown recognition is always on, not just a one-off input rule. If you have `x- text` and delete the `x`, you get a list item, the same thing the Markdown means, not a paragraph that happens to contain `- text`. **This holds even for really complex Markdown.**
- When you open an existing file, blocks you don’t touch are written back as they were. Blocks you do edit are re-serialized using the syntax they were originally written with (bullet character `-`/`*`/`+`, fence style, leading space, and so on), so the file stays close to what you actually wrote.

It’s very early alpha, and the APIs will change. There are probably still plenty of bugs, and parts of the code haven’t been fully refactored yet. Would love to hear what you think!

---

<div class="post-metadata">

**Author:** ![bdbch](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/bdbch/32/4736_2.png) [@bdbch](https://discuss.prosemirror.net/u/bdbch)\
**Post date:** [November 5, 2026, 10:41pm UTC](https://discuss.prosemirror.net/t/kagami-typora-style-live-markdown-editing-on-prosemirror/9126/2 "2026-11-05T22:41:37Z")

</div>

Interesting! I’m actually working on the same thing right now but for CodeMirror. What’s the reason why you went with ProseMirror on this instead of something like CodeMirror? Imo it’s a bit more straightforward using the actual Markdown & then render the richtext via decorations on valid markdown ranges instead of doing it the other way around (rendering richtext & turning it back to markdown when the cursor is inside, etc.)

---

<div class="post-metadata">

**Author:** ![kkshinkai](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kkshinkai/32/3401_2.png) [@kkshinkai](https://discuss.prosemirror.net/u/kkshinkai)\
**Post date:** [November 6, 2026, 1:32am UTC](https://discuss.prosemirror.net/t/kagami-typora-style-live-markdown-editing-on-prosemirror/9126/3 "2026-11-06T01:32:47Z")

</div>

Layout matters a lot to me. I see it as part of the live-preview experience: paragraphs should have proper spacing, and quotes and lists should look like nested boxes. That’s where I don’t think building on a source editor works.

I haven’t tried this in CodeMirror myself, and I don’t know it well enough to say it can’t be done. But the precedents are bad. In Obsidian’s editor and HyperMD, nested blocks that are even a little complex fall apart. My guess is that this kind of editor just wasn’t something CodeMirror was designed for.

The problem is the model. A source editor lays the document out as lines, and all you can tune is the size of characters and rows. A Markdown document is a tree, though. A quote or a list item is a box around its children, but in the source it’s cut into a marker at the start of every line it spans:

- Two-space and four-space indentation in a list item mean the same thing and should look the same. But the spaces are characters you can see and type, so you end up stretching and shrinking characters to fake the indent.

- A quote is one box with one continuous bar down its left side. In source, the “bar” is a \> typed at the start of each line, and Markdown doesn’t require those to line up or even be there:

- The space between paragraphs is a margin, but in source it’s a blank line. You can shrink that row, but when the first character is typed on it, the row jumps back to full height.

So Kagami keeps blocks as a ProseMirror tree and draws them as real boxes. Inline text is still edited as Markdown source with the syntax hidden outside the selection, which is the part where your approach is right.
