prosemirror-model

The persistent document model and schema system at the core of the ProseMirror rich-text editor.

Library
npm
v1.25.11
340stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
42/100Fair
Development Activity8
Maintenance0
Community80
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
77/100Good
Architecture88
Code Quality82
Innovation78
Learning Curve58

prosemirror-model implements the document model that every ProseMirror-based editor is built on: an immutable tree of Node and Fragment instances, together with the Schema system that defines which node and mark types a document may contain and how they nest. It underpins collaborative editors like TipTap, Atlassian’s editor, and countless custom rich-text tools that need a version-controllable, diffable representation of structured content rather than raw HTML.

Because nodes and fragments are persistent (never mutated in place), edits produce new document versions that share unchanged structure with the old one — a foundation that operational-transform and CRDT-based collaboration layers (prosemirror-collab, y-prosemirror) build directly on top of. The package also ships a bidirectional DOM bridge (DOMParser and DOMSerializer) so schemas can round-trip through contentEditable without the editor ever touching raw HTML strings directly.

What You Get

  • Node and Fragment classes: an immutable tree structure representing a document’s content, size, and children
  • Schema, NodeSpec, and MarkSpec APIs for declaring the node/mark types, attributes, and content-expression rules a document must obey
  • ContentMatch for validating and auto-completing sequences of child nodes against a schema’s content expressions
  • DOMParser and DOMSerializer for converting between the document model and browser DOM/HTML, driven by declarative parse and serialization rules
  • ResolvedPos and NodeRange for resolving integer document positions into structured, depth-aware location info
  • Slice and replace() for representing and applying structural edits (cut/paste-style content splicing) across the document tree

Common Use Cases

  • Building a custom rich-text or structured-content editor on top of ProseMirror’s view and state packages
  • Defining a constrained document schema (e.g. only headings, paragraphs, and specific inline marks) for a CMS or comment editor
  • Implementing collaborative editing where documents need a diffable, structure-sharing representation for OT/CRDT syncing
  • Converting between HTML and a validated document tree when importing/exporting content from a rich-text field

Under The Hood

Architecture The module is organized as a small set of tightly coupled classes rather than layered subsystems: node.ts defines Node (and its leaf TextNode variant), fragment.ts defines Fragment as the ordered child-list container each Node holds, and mark.ts defines Mark for inline formatting attached to nodes — together forming an immutable tree where every mutation-looking operation (Node.replace, Fragment.append, etc.) returns a new instance built via comparedeep.ts’s structural-sharing helpers rather than mutating in place. schema.ts defines Schema, NodeType, and MarkType, which own the NodeSpec/MarkSpec content-expression strings; those expressions are compiled by content.ts’s ContentMatch (a hand-rolled NFA→DFA compiler: parseExpr/nfa/dfa functions) into a matcher used both to validate document trees at construction time and to auto-fill required content. resolvedpos.ts’s ResolvedPos resolves a flat integer document offset into a full ancestor path, letting replace.ts’s Slice/replace() implement schema-aware content splicing (used for cut/paste-like operations) by walking up and down the resolved position’s ancestor chain to find the correct open/close boundaries. from_dom.ts (DOMParser, ~850 lines, the largest file in the module) and to_dom.ts (DOMSerializer) form the DOM boundary layer, converting between the tree and the browser DOM via declarative ParseRule/DOMOutputSpec objects rather than imperative walking code, so schema authors describe HTML shape declaratively instead of writing parser logic themselves.

Tech Stack prosemirror-model is a zero-runtime-framework TypeScript library (100% TypeScript per GitHub’s language breakdown) with exactly one runtime dependency: orderedmap (^2.0.0), used internally by Schema to keep node/mark type definitions in an order-preserving map. It has no build-time bundler config of its own — package.json’s prepare script (pm-buildhelper src/index.ts) delegates compilation and multi-format output (dist/index.js as ESM, dist/index.cjs as CJS, dist/index.d.ts for types) to @prosemirror/buildhelper, a shared tool used across the whole ProseMirror monorepo family, and the package is declared “type”: “module” with sideEffects: false so bundlers can tree-shake it. Test-only dependencies are jsdom (^20.0.0, to exercise the DOM parser/serializer without a real browser) and prosemirror-test-builder (a companion ProseMirror package providing schema/document test fixtures), run via the pm-runtests script from the same buildhelper toolchain rather than a general-purpose test runner config checked into this repo.

Code Quality Tests live under test/ as one file per module (test-node.ts, test-content.ts, test-dom.ts, test-replace.ts, test-resolve.ts, test-slice.ts, test-mark.ts, test-diff.ts) using the minimal ist assertion library and Mocha-style describe/it blocks, exercising both the public API and edge cases like custom toDebugString/leafText overrides in test-node.ts — coverage reads as thorough for a module this central, though there’s no CI config or coverage report checked into this specific clone to verify enforced thresholds. Source files are consistently documented with /// doc comments used to generate the published API reference (visible throughout node.ts, schema.ts, and content.ts), and error handling is explicit rather than silent: RangeError is thrown with descriptive messages for invalid attributes (schema.ts’s checkAttrs) and invalid content (content.ts, replace.ts’s ReplaceError), so schema/document misuse fails fast at construction time instead of producing corrupt trees. Naming is terse but consistent with the rest of the ProseMirror ecosystem (nodeSize, childCount, resolve), and TypeScript’s strict typing (readonly properties throughout Node/Fragment/Mark) enforces the immutability contract at compile time rather than relying on documentation alone.

API Design The public API favors a small number of orthogonal, composable primitives over convenience wrappers: Node, Fragment, Schema, and Slice cover essentially every editing operation, and higher-level packages (prosemirror-transform, prosemirror-state) build entirely on top of this module’s exported surface rather than reaching into internals — index.ts’s export list is deliberately narrow. Getting started requires defining a Schema with NodeSpec/MarkSpec objects before anything else, which is more upfront boilerplate than schema-less alternatives like plain contentEditable, but that investment is what makes the rest of the API (matchType, contentMatchAt, DOMParser.fromSchema) type-safe and validated. Documentation is dense and reference-oriented — the /// comments in src/*.ts are extracted into the published API docs on prosemirror.net referenced from README.md and src/README.md — favoring precision over tutorial-style hand-holding, which fits an audience of editor-framework authors more than end-application developers dropping the package in for a five-minute integration.

Used by 17 apps in this directory

TypeScript
51%
MIT

Anarlog

Note Taking · AI Assistants · Productivity

9,087

Anarlog is an open-source, local-first AI meeting notetaker that records, transcribes, and summarizes meetings entirely on your device — no cloud lock-in, no mandatory account, and every note saved as a plain markdown file you own forever.

View details
86
Repo Health
77
Technical
69
Dependency
Built with
TypeScript51%
Rust38%
Updated today
Ruby
49%
Other

Chatwoot

Customer Support

35,974

Open-source omnichannel customer support platform with AI-powered agents, live chat, and self-hosting — a full Intercom and Zendesk alternative.

View details
95
Repo Health
78
Technical
72
Dependency
Built with
Ruby49%
Vue26%
JavaScript22%
Updated today
Swift
64%
GPL 3.0

cmux

Developer Tools · AI Development

26,221

A native, Ghostty-based macOS terminal with vertical tabs, agent-aware notifications, and a scriptable browser built for running many parallel AI coding agent sessions instead of juggling tmux panes.

View details
84
Repo Health
81
Technical
72
Dependency
Built with
Swift64%
Rust14%
Updated today
Ruby
62%
GPL 2.0

Discourse

Community

47,672

Open-source community platform with dynamic trust levels, real-time chat, and a powerful plugin architecture for self-hosted forums.

View details
89
Repo Health
89
Technical
67
Dependency
Built with
Ruby62%
JavaScript31%
Updated today
TypeScript
92%
MIT

Dittofeed

Marketing · Automation

2,903

Open-source omni-channel customer engagement platform for automating transactional and marketing messages via email, SMS, WhatsApp, Slack, and mobile push.

View details
54
Repo Health
75
Technical
63
Dependency
Built with
TypeScript92%
Updated 4 months ago
TypeScript
72%
Other

Epicenter

Knowledge Management · Note Taking · Developer Tools

4,761

A local-first monorepo led by Whispering, an open-source speech-to-text app, built on an MIT toolkit that turns your data into plain Markdown and SQLite files you own instead of a database you rent.

View details
88
Repo Health
90
Technical
68
Dependency
Built with
TypeScript72%
Svelte15%
Updated today
TypeScript
76%
Other

Joplin

Note Taking

56,003

The privacy-first, open-source note-taking app with end-to-end encrypted sync, AI assistance, and a powerful plugin ecosystem across every platform.

View details
93
Repo Health
87
Technical
62
Dependency
Built with
TypeScript76%
JavaScript15%
Updated yesterday
Scala
63%
AGPL 3.0

lila (Lichess)

Community

18,642

The forever-free, ad-free, open-source chess server powering millions of real-time games, AI analysis, puzzles, and tournaments worldwide.

View details
89
Repo Health
80
Technical
78
Dependency
Built with
Scala63%
TypeScript26%
Updated today
JavaScript
44%
Other

LimeSurvey

Forms Surveys

3,698

The world's most flexible open-source survey platform with 900+ templates, conditional logic, 80+ languages, and full GDPR compliance for any scale.

View details
86
Repo Health
62
Technical
62
Dependency
Built with
JavaScript44%
PHP34%
CSS12%
Updated today

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search