{"slug": "prosemirror", "name": "ProseMirror", "category": "dev-libs", "category_name": "Libraries and frameworks", "description": "", "recommenders": 5, "commenters": 14, "warners": 3, "score": 3.414, "rising": -1.64, "first": "2025-11-17", "latest": "2026-09-02", "why": "Lexical, Slate, and ProseMirror (especially ProseMirror, in our opinion!) are all excellent rich text libraries", "why_is_quote": true, "has_verdict": false, "sentiment": {"recommend": 4, "neutral": 7, "compare": 1, "warn": 3}, "spark": [0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0], "listed": true, "loved": [], "caveat": "", "short_quote": "Lexical, Slate, and ProseMirror (especially ProseMirror, in our opinion!) are all excellent rich text libraries", "kind": "", "icon": true, "domain": null, "github_repo": "github.com/prosemirror/website", "official_url": "https://prosemirror.net", "pricing": "", "aliases": ["ProseMirror"], "verdict": null, "praise": [{"label": "", "summary": "", "quotes": [{"id": 758912784, "item_id": 47432049, "url": "https://news.ycombinator.com/item?id=47432049", "by": "antics", "date": "2026-03-18", "version": null, "stance": "recommend", "quote": "prosemirror-collab does give me offline editing. I use it literally every day, entirely without issue.", "excerpt": "But Kevin, prosemirror-collab does give me offline editing. I use it literally every day, entirely without issue. I write offline on different devices, and whenever I come online, it all syncs up. No issues. It does not give me p2p topology. Is that what you mean?", "context": "", "use_case": "Offline collaborative editing", "switched_from": "", "story": "Lies I was told about collaborative editing, Part 2: Why we don't use Yjs"}, {"id": 758860002, "item_id": 47428750, "url": "https://news.ycombinator.com/item?id=47428750", "by": "smoores", "date": "2026-03-18", "version": null, "stance": "recommend", "quote": "Lexical, Slate, and ProseMirror (especially ProseMirror, in our opinion!) are all excellent rich text libraries", "excerpt": "Hey folks! Handle with Care is a software collective that builds and maintains open source rich text editing libraries, including React ProseMirror [1]. We all came from The New York Times\u2019 content management system team, and we spend a lot of time thinking about rich text and collaborative editing. Now we\u2019re working on something new: Pitter Patter will be a fully featured collaborative rich text editing toolkit, wit", "context": "", "use_case": "", "switched_from": "", "story": "We're building a better rich text editing toolkit"}, {"id": 758477985, "item_id": 47404874, "url": "https://news.ycombinator.com/item?id=47404874", "by": "antics", "date": "2026-03-16", "version": null, "stance": "recommend", "quote": "They also also are MUCH better at representing the user intent", "excerpt": "I know it seems that way, but it's actually not 80% of the way to a CRDT because rich text CRDTs are an open research problem. Yjs instead models the document as an XML tree and then attempts to recreate the underlying rich text transaction. This is much, much harder than it looks, and it's inherently lossy, and this fundamental impedance mismatch is one of the core complaints of this article. Some progress is being ", "context": "", "use_case": "", "switched_from": "", "story": "Lies I was told about collaborative editing, Part 2: Why we don't use Yjs"}, {"id": 758345760, "item_id": 47396610, "url": "https://news.ycombinator.com/item?id=47396610", "by": "antics", "date": "2026-03-16", "version": null, "stance": "recommend", "quote": "it, too, is generally not a lot of code", "excerpt": "Author here. I'll actually defend this. Most of the subtlety of this part is actually in document schema version mismatches, and you'd handle that at client connect, generally, since we want the server to dictate the schema version you're using. In general, the client implementation of collab is pretty simple. Nearly all of the subtlety lies in the server. But it, too, is generally not a lot of code, see for example ", "context": "Author of the linked post", "use_case": "Collaborative rich-text editing", "switched_from": "", "story": "Lies I was told about collaborative editing, Part 2: Why we don't use Yjs"}]}], "caveats": [{"label": "", "summary": "", "quotes": [{"id": 780417712, "item_id": 48776107, "url": "https://news.ycombinator.com/item?id=48776107", "by": "andrewingram", "date": "2026-07-03", "version": null, "stance": "warn", "quote": "One thing i've struggled with with Prosemirror (via TipTap)", "excerpt": "One thing i've struggled with with Prosemirror (via TipTap) is that I very often need to interact with JSON representation of the document programmatically to extract data from it, this means I need (okay, strongly prefer) a statically-typed representation of it. Prosemirror doesn't really have any mechanism to do this, so i've ended up doing one of these two things: 1. Define the schema twice, once using Prosemirror", "context": "", "use_case": "Rich text editor framework", "switched_from": "", "story": "Wordgard: The new in-browser rich-text editor from the creator of ProseMirror"}, {"id": 773554179, "item_id": 48347136, "url": "https://news.ycombinator.com/item?id=48347136", "by": "pbjerkeseth", "date": "2026-05-31", "version": null, "stance": "warn", "quote": "so I guess Ill close the door on that idea", "excerpt": "No problem, I actually went through a similar path of trying milkdown/tiptap/a few others as the core for my own editor needs but kept running into into issues where the abstractions got in the way eventually. I was thinking about using ProseMirror for a custom 'one big text file' concept so I guess Ill close the door on that idea and give this a try.", "context": "", "use_case": "", "switched_from": "", "story": "Show HN: Atomic Editor \u2013 Obsidian-style live preview for CodeMirror 6"}, {"id": 758579793, "item_id": 47411237, "url": "https://news.ycombinator.com/item?id=47411237", "by": "kevinjahns", "date": "2026-03-17", "version": null, "stance": "warn", "quote": "which ironically talks about how hard prosemirror-collab is to debug", "excerpt": "Hi, the author of Yjs here. Thanks, Nick, for chiming in! As this article is blowing up now, I want to address a few points. I, too, feel the need for simplicity over overly complex solutions - and I found it in CRDTs. They beautifully allow me to reason about conflicts - so that my users don't have to. Very few people can design a custom conflict resolution algorithm for an application. Yjs is a general-purpose fram", "context": "", "use_case": "", "switched_from": "", "story": "Lies I was told about collaborative editing, Part 2: Why we don't use Yjs"}]}], "who": [{"by": "antics", "context": "Author of the linked post", "url": "https://news.ycombinator.com/item?id=47396610", "date": "2026-03-16"}], "tags": [], "use_cases": ["rich text editor framework", "rich-text editor framework", "document editing", "offline collaborative editing", "collaborative rich-text editing", "rich text editing"], "compared": [{"slug": "tiptap", "name": "Tiptap", "co": 4, "switched_from": 0, "switched_to": 0}, {"slug": "yjs", "name": "Yjs", "co": 4, "switched_from": 0, "switched_to": 0}, {"slug": "lexical", "name": "Lexical", "co": 3, "switched_from": 0, "switched_to": 0}], "makers": [], "threads": [{"url": "https://news.ycombinator.com/item?id=48772573", "title": "Wordgard: The new in-browser rich-text editor from the creator of ProseMirror", "mentions": 6}, {"url": "https://news.ycombinator.com/item?id=47359712", "title": "Lies I was told about collaborative editing, Part 2: Why we don't use Yjs", "mentions": 6}, {"url": "https://news.ycombinator.com/item?id=49524863", "title": "Fine, I'll build my own text editor", "mentions": 1}, {"url": "https://news.ycombinator.com/item?id=48492210", "title": "Claude Fable 5: mid-tier results on coding tasks", "mentions": 1}, {"url": "https://news.ycombinator.com/item?id=48345201", "title": "Show HN: Atomic Editor \u2013 Obsidian-style live preview for CodeMirror 6", "mentions": 1}, {"url": "https://news.ycombinator.com/item?id=47428749", "title": "We're building a better rich text editing toolkit", "mentions": 1}], "sentiment_by_month": {"2025-11": {"neutral": 1}, "2025-12": {}, "2026-01": {}, "2026-02": {"neutral": 1}, "2026-03": {"recommend": 2, "neutral": 2, "warn": 1}, "2026-04": {}, "2026-05": {"warn": 1}, "2026-06": {"neutral": 1}, "2026-07": {"compare": 1, "neutral": 1, "warn": 1, "recommend": 2}, "2026-08": {}, "2026-09": {"neutral": 1}, "2026-10": {}}, "versions": [], "version_unnamed": 0, "family_ref": null, "runs_on": null, "lines": [], "quotes": [{"id": 792555041, "item_id": 49534690, "url": "https://news.ycombinator.com/item?id=49534690", "by": "Isofarro", "date": "2026-09-02", "version": null, "stance": "neutral", "quote": "Haverbeke went on to create CodeMirror and ProseMirror.", "excerpt": "The author travels the same path that ended up eventually with VS Code. Reminds me strongly of Marjin Haverbeke's talk at Full Frontal conf in 2011: https://ffconf.org/talks/respectable-code-editing-in-the-browser/ - Using Canvas, then contenteditable, and then DOM. Haverbeke went on to create CodeMirror and ProseMirror.", "context": "", "use_case": "", "switched_from": "", "story": "Fine, I'll build my own text editor"}, {"id": 780419633, "item_id": 48776227, "url": "https://news.ycombinator.com/item?id=48776227", "by": "keepupnow", "date": "2026-07-03", "version": null, "stance": "recommend", "quote": "", "excerpt": "You are wrong, Lexical it is not in maintenance mode and continues to receive commits from contributors. 24k stars and counting. https://github.com/facebook/lexical", "context": "", "use_case": "", "switched_from": "", "story": "Wordgard: The new in-browser rich-text editor from the creator of ProseMirror"}, {"id": 780417968, "item_id": 48776123, "url": "https://news.ycombinator.com/item?id=48776123", "by": "nicce", "date": "2026-07-03", "version": null, "stance": "recommend", "quote": "", "excerpt": "Seems like the contribution graph is on the highest for long time: https://github.com/facebook/lexical/graphs/contributors?from=6%2F29%2F2024 But Claude is playing part of it.", "context": "", "use_case": "", "switched_from": "", "story": "Wordgard: The new in-browser rich-text editor from the creator of ProseMirror"}, {"id": 780417712, "item_id": 48776107, "url": "https://news.ycombinator.com/item?id=48776107", "by": "andrewingram", "date": "2026-07-03", "version": null, "stance": "warn", "quote": "One thing i've struggled with with Prosemirror (via TipTap)", "excerpt": "One thing i've struggled with with Prosemirror (via TipTap) is that I very often need to interact with JSON representation of the document programmatically to extract data from it, this means I need (okay, strongly prefer) a statically-typed representation of it. Prosemirror doesn't really have any mechanism to do this, so i've ended up doing one of these two things: 1. Define the schema twice, once using Prosemirror", "context": "", "use_case": "Rich text editor framework", "switched_from": "", "story": "Wordgard: The new in-browser rich-text editor from the creator of ProseMirror"}, {"id": 780396976, "item_id": 48774811, "url": "https://news.ycombinator.com/item?id=48774811", "by": "Imustaskforhelp", "date": "2026-07-03", "version": null, "stance": "neutral", "quote": "doesn't seem like Prosemirror is going unmaintained. It will continue to be maintained", "excerpt": "Obligatory xkcd: https://xkcd.com/2347/ but as @john_strinlai as I have said it doesn't seem like Prosemirror is going unmaintained. It will continue to be maintained but I think its worth thinking about the structure of the whole thing being so similar to the xkcd which is what might be the scary part of it.", "context": "", "use_case": "", "switched_from": "", "story": "Wordgard: The new in-browser rich-text editor from the creator of ProseMirror"}, {"id": 780379169, "item_id": 48773698, "url": "https://news.ycombinator.com/item?id=48773698", "by": "exceptione", "date": "2026-07-03", "version": null, "stance": "recommend", "quote": "", "excerpt": "For people who have dealt with react, this part might give some insight into that topic (https://wordgard.net/docs/prosemirror/#h-transactions-and-changes)? Nevertheless, it would be good if this could be addressed in the docs. I am not sure if this makes things easier for react interop, but this piece might be of interest too: > One of the biggest mistake blunders in ProseMirror is that the editor view does not get ", "context": "", "use_case": "Rich-text editor framework", "switched_from": "", "story": "Wordgard: The new in-browser rich-text editor from the creator of ProseMirror"}, {"id": 780377776, "item_id": 48773611, "url": "https://news.ycombinator.com/item?id=48773611", "by": "exceptione", "date": "2026-07-03", "version": null, "stance": "compare", "quote": "it seems that switching means doing quite some work", "excerpt": "I think most people would love to the know the 'why'. This page discusses differences with prosemirror and is the closest I got to that question: (https://wordgard.net/docs/prosemirror/). One thing to note is that there is not an upgrade path. Many concepts are shared with prosemirror, but it seems that switching means doing quite some work (correct me if I am wrong). Obsidian is based on Code Mirror so I guess they ", "context": "", "use_case": "", "switched_from": "", "story": "Wordgard: The new in-browser rich-text editor from the creator of ProseMirror"}, {"id": 775936274, "item_id": 48496017, "url": "https://news.ycombinator.com/item?id=48496017", "by": "practal", "date": "2026-06-11", "version": null, "stance": "neutral", "quote": "how I sync between the \"livemodel\" (in-memory replica of database state) and ProseMirror's model", "excerpt": "I am quite impressed with Fable 5. I used the \u00a318 subscription, and asked it to convert the document processing of Practal Zero [1] from running in the same thread as the UI to a worker thread. Just two days before I gave the same task to Codex, and the result was not really nice: it would copy the entire document to the worker thread as a snapshot for processing, and so on. Fable instead realised that it could make ", "context": "", "use_case": "document editing", "switched_from": "", "story": "Claude Fable 5: mid-tier results on coding tasks"}, {"id": 773554179, "item_id": 48347136, "url": "https://news.ycombinator.com/item?id=48347136", "by": "pbjerkeseth", "date": "2026-05-31", "version": null, "stance": "warn", "quote": "so I guess Ill close the door on that idea", "excerpt": "No problem, I actually went through a similar path of trying milkdown/tiptap/a few others as the core for my own editor needs but kept running into into issues where the abstractions got in the way eventually. I was thinking about using ProseMirror for a custom 'one big text file' concept so I guess Ill close the door on that idea and give this a try.", "context": "", "use_case": "", "switched_from": "", "story": "Show HN: Atomic Editor \u2013 Obsidian-style live preview for CodeMirror 6"}, {"id": 758912784, "item_id": 47432049, "url": "https://news.ycombinator.com/item?id=47432049", "by": "antics", "date": "2026-03-18", "version": null, "stance": "recommend", "quote": "prosemirror-collab does give me offline editing. I use it literally every day, entirely without issue.", "excerpt": "But Kevin, prosemirror-collab does give me offline editing. I use it literally every day, entirely without issue. I write offline on different devices, and whenever I come online, it all syncs up. No issues. It does not give me p2p topology. Is that what you mean?", "context": "", "use_case": "Offline collaborative editing", "switched_from": "", "story": "Lies I was told about collaborative editing, Part 2: Why we don't use Yjs"}, {"id": 758860002, "item_id": 47428750, "url": "https://news.ycombinator.com/item?id=47428750", "by": "smoores", "date": "2026-03-18", "version": null, "stance": "recommend", "quote": "Lexical, Slate, and ProseMirror (especially ProseMirror, in our opinion!) are all excellent rich text libraries", "excerpt": "Hey folks! Handle with Care is a software collective that builds and maintains open source rich text editing libraries, including React ProseMirror [1]. We all came from The New York Times\u2019 content management system team, and we spend a lot of time thinking about rich text and collaborative editing. Now we\u2019re working on something new: Pitter Patter will be a fully featured collaborative rich text editing toolkit, wit", "context": "", "use_case": "", "switched_from": "", "story": "We're building a better rich text editing toolkit"}, {"id": 758686608, "item_id": 47417913, "url": "https://news.ycombinator.com/item?id=47417913", "by": "nickthesick", "date": "2026-03-17", "version": null, "stance": "neutral", "quote": "We will have better support for ProseMirror's position mapping", "excerpt": "Yes, we are still using XML to represent the document content, to represent the document as a flat list would require some research into something like Automerge's Block markers https://automerge.org/docs/reference/under-the-hood/rich-text-schema/ which we don't have the funding to look into right now, but hope to work towards in the future. We will have better support for ProseMirror's position mapping, but I'm not ", "context": "", "use_case": "", "switched_from": "", "story": "Lies I was told about collaborative editing, Part 2: Why we don't use Yjs"}, {"id": 758579793, "item_id": 47411237, "url": "https://news.ycombinator.com/item?id=47411237", "by": "kevinjahns", "date": "2026-03-17", "version": null, "stance": "warn", "quote": "which ironically talks about how hard prosemirror-collab is to debug", "excerpt": "Hi, the author of Yjs here. Thanks, Nick, for chiming in! As this article is blowing up now, I want to address a few points. I, too, feel the need for simplicity over overly complex solutions - and I found it in CRDTs. They beautifully allow me to reason about conflicts - so that my users don't have to. Very few people can design a custom conflict resolution algorithm for an application. Yjs is a general-purpose fram", "context": "", "use_case": "", "switched_from": "", "story": "Lies I was told about collaborative editing, Part 2: Why we don't use Yjs"}, {"id": 758558626, "item_id": 47409914, "url": "https://news.ycombinator.com/item?id=47409914", "by": "nickthesick", "date": "2026-03-17", "version": null, "stance": "neutral", "quote": "rewriting the y-prosemirror binding today", "excerpt": "FWIW, I'm literally working on rewriting the y-prosemirror binding today with Kevin Jahns, the creator of Y.js and wrote the initial binding. Yes, the current binding has it's flaws, but we hope to flush out the most egregious of them with a completely different design which I made a presentation about at FOSDEM this year: https://fosdem.org/2026/schedule/event/8VKQXR-blocknote-yjs-prosemirror/", "context": "", "use_case": "", "switched_from": "", "story": "Lies I was told about collaborative editing, Part 2: Why we don't use Yjs"}, {"id": 758485408, "item_id": 47405338, "url": "https://news.ycombinator.com/item?id=47405338", "by": "mweidner", "date": "2026-03-16", "version": null, "stance": "neutral", "quote": "", "excerpt": "Your part 1 post was one of the inspirations for that :) Specifically, it inspired the question: how can one let programmers customize the way edits are processed, to avoid e.g. the \"colour\" -> \"u\" anomaly*, without violating CRDT/OTs' strict algebraic requirements? To which the answer is: find a way to get rid of those requirements. *This is not just common behavior, but also features in a formal specification [1] o", "context": "", "use_case": "", "switched_from": "", "story": null}, {"id": 758477985, "item_id": 47404874, "url": "https://news.ycombinator.com/item?id=47404874", "by": "antics", "date": "2026-03-16", "version": null, "stance": "recommend", "quote": "They also also are MUCH better at representing the user intent", "excerpt": "I know it seems that way, but it's actually not 80% of the way to a CRDT because rich text CRDTs are an open research problem. Yjs instead models the document as an XML tree and then attempts to recreate the underlying rich text transaction. This is much, much harder than it looks, and it's inherently lossy, and this fundamental impedance mismatch is one of the core complaints of this article. Some progress is being ", "context": "", "use_case": "", "switched_from": "", "story": "Lies I was told about collaborative editing, Part 2: Why we don't use Yjs"}, {"id": 758345760, "item_id": 47396610, "url": "https://news.ycombinator.com/item?id=47396610", "by": "antics", "date": "2026-03-16", "version": null, "stance": "recommend", "quote": "it, too, is generally not a lot of code", "excerpt": "Author here. I'll actually defend this. Most of the subtlety of this part is actually in document schema version mismatches, and you'd handle that at client connect, generally, since we want the server to dictate the schema version you're using. In general, the client implementation of collab is pretty simple. Nearly all of the subtlety lies in the server. But it, too, is generally not a lot of code, see for example ", "context": "Author of the linked post", "use_case": "Collaborative rich-text editing", "switched_from": "", "story": "Lies I was told about collaborative editing, Part 2: Why we don't use Yjs"}, {"id": 750723282, "item_id": 46920205, "url": "https://news.ycombinator.com/item?id=46920205", "by": "mweidner", "date": "2026-02-06", "version": null, "stance": "neutral", "quote": "which it converts to a separate ProseMirror tree on each update", "excerpt": "Managing \"a flat-ish collection of nodes\" that can be moved around (without merely deleting and re-inserting nodes) is tricky because of how paragraphs can be split and merged. Notion tackled this for their offline mode: https://www.youtube.com/watch?v=AKDcWRkbjYs If you take that as a solved problem, do your concerns change? > Selection & Cursors: Selection across regions is notoriously hard. If \"Region A\" and \"Regi", "context": "", "use_case": "", "switched_from": "", "story": null}, {"id": 735234912, "item_id": 45952182, "url": "https://news.ycombinator.com/item?id=45952182", "by": "pdubroy", "date": "2025-11-17", "version": null, "stance": "neutral", "quote": "construct a ProseMirror transaction that would turn the old tree into the new one", "excerpt": "It's explained in the post: > Then, my plan was to construct a ProseMirror transaction that would turn the old tree into the new one. To do that, it\u2019s helpful to know which nodes appeared in the old document, but not the new one. So, it's not actually about reclaiming the memory. It's about taking some action on the nodes that will be reclaimed. It's akin to a destructor/finalizer, but I need that to happen synchrono", "context": "", "use_case": "Rich text editing", "switched_from": "", "story": "Garbage collection is useful"}]}