Profile
Back to NewsBack
GitHub Trending 5 min
Reader Mode
domternal/domternal: Modern, extensible rich text editor toolkit built on ProseMirror. Classic and Notion-style editors out of the box. Or go headless and assemble from 65+ tree-shakeable extensions. First-class wrappers for Angular, React, Vue, and

domternal/domternal: Modern, extensible rich text editor toolkit built on ProseMirror. Classic and Notion-style editors out of the box. Or go headless and assemble from 65+ tree-shakeable extensions. First-class wrappers for Angular, React, Vue, and

8 hours ago

Domternal

Domternal Editor</a>

A rich text editor toolkit built on ProseMirror, with a headless core and first-class Angular, React, Vue, and Vanilla components. Take the core alone and drive the DOM yourself, add the toolbar and theme for a finished editor, or mount the components for your framework. Notion-style block editing, drag handle, slash menu and floating outline are included. JavaScript exports are tree-shakeable; the optional theme ships as one complete CSS stylesheet.

License: MIT</a> CI</a> codecov</a> npm</a>

Website · Getting Started · Packages & Bundle Size

Live examples - full editors for Angular, React, Vue, and Vanilla, editable in the browser

Features

  • Headless core - use with any framework or vanilla JS/TS
  • Angular components - editor, toolbar, bubble menu, floating menu, emoji picker, notion color picker (signals, OnPush, zoneless-ready)
  • React components - composable Domternal component, toolbar, bubble menu, floating menu, emoji picker, notion color picker, custom node views (React 18+)
  • Vue components - composable Domternal component, useEditor/useEditorState composables, toolbar, bubble menu, floating menu, emoji picker, notion color picker, custom node views (Vue 3.3+)
  • Vanilla wrapper - framework-free class-based API for Astro, Svelte, Solid, plain HTML, and Web Components - editor, toolbar, bubble menu, floating menu, emoji picker, notion color picker
  • Notion-style block UX - drag-to-reorder, block context menu, slash command, smart paste, keyboard reorder, floating Table of Contents, from @domternal/extension-block-controls and @domternal/extension-toc, with preset: 'notion' for the layout and preset-aware behavior
  • Print to paper or PDF - printDocument() leaves your app's chrome off the page, with optional image/font preparation and eligible repeated table headers; the theme's paper layer also applies to Ctrl/Cmd+P
  • 70+ extensions across core and 11 extension packages - nodes, marks, and behavior extensions
  • 130+ chainable commands - editor.chain().focus().toggleBold().run()
  • Full table support - cell merging, column resize, row/column controls, cell toolbar and opt-in row heights, cell padding/borders and page-break preferences
  • Optional image geometry: crop, rotate and mirror images without changing source bytes
  • Editable document notes: opt-in footnote/endnote bodies and references in ordinary editor JSON, with navigation and undo
  • Office paste cleanup: opt-in Word and Google Docs HTML normalization, preserve/adapt formatting, list reconstruction, and localized feedback about content the editor cannot keep
  • Optional custom list labels: native counters, bounded compound templates, Unicode bullets and local PNG markers, with matching collaborative schemas and companion CSS for standalone HTML
  • Tree-shakeable JavaScript - import only the JavaScript exports you use; the optional @domternal/theme deliberately ships one complete stylesheet
  • ~95 KiB minified and gzipped (own code), ~176 KiB minified and gzipped total with runtime dependencies: see Packages for the full bundle breakdown
  • TypeScript first - every package builds under strict, with exactOptionalPropertyTypes and noUncheckedIndexedAccess
  • 17,000+ automated test executions - unit coverage and a Playwright matrix across four demo apps
  • Light and dark theme - 150+ CSS custom properties for full visual control
  • Optional text contrast: improve literal text colors on supported backgrounds while preserving authored colors in stored content, HTML, clipboard output and print
  • Per-editor UI localization: replace labels at creation or runtime, keep English fallback text, and opt into complete German catalogs
  • Inline styles export - getHTML({ styled: true }) produces inline CSS ready for email clients, CMS, and Google Docs
  • Headless and SSR helpers - createSchema for shared editor/worker schemas, plus generateHTML, generateJSON and generateText for server-side conversion

Quick Start

Headless (Vanilla JS/TS)

pnpm add @domternal/core
import { Editor, Document, Text, Paragraph, Bold, Italic, Underline } from '@domternal/core';

const editor = new Editor({ element: document.getElementById('editor')!, extensions: [Document, Text, Paragraph, Bold, Italic, Underline], content: '<p>Hello <strong>World</strong>!</p>', });

The example above wires the minimum schema by hand to show the headless model; in practice use StarterKit for a batteries-included setup with headings, lists, code blocks, history, and more.

Getting Started Guide - headless core, themed UI with toolbar, and Angular/React/Vue component setup

Word and Google Docs paste

Add the optional @domternal/extension-paste-cleanup package alongside your editor:

pnpm add @domternal/extension-paste-cleanup
import { Editor, StarterKit } from '@domternal/core';
import { PasteCleanup } from '@domternal/extension-paste-cleanup';

const editor = new Editor({ element: document.getElementById('editor')!, extensions: [StarterKit, PasteCleanup.configure({ formatting: 'preserve' })], });

Register the same extension in Angular, React, Vue, or Vanilla. preserve keeps supported source formatting; adapt uses the receiving editor's formatting. Register Table, Image, and other extensions for content your editor should keep. The built-in notice and onPasteResult report losses, and the standalone /html entry normalizes HTML without a DOM. PasteCleanup is not part of StarterKit or the wrappers' default extensions. It handles clipboard HTML, not .docx files. See the package README for options, image handling, feedback, and source-specific limits.

Localization

Every editor starts with English UI text and accepts its own i18n configuration. German catalogs are available as optional /locales/de imports from core and each extension that owns UI messages. Merge only the catalogs for the features you use:

import type { I18nOptions } from '@domternal/core';
import {
  deMessages as coreDe,
  deSearchAliases as coreAliasesDe,
} from '@domternal/core/locales/de';
import {
  deMessages as tableDe,
  deSearchAliases as tableAliasesDe,
} from '@domternal/extension-table/locales/de';

const german = { locale: 'de', messages: { ...coreDe, ...tableDe }, searchAliases: { ...coreAliasesDe, ...tableAliasesDe }, } satisfies I18nOptions;

editor.i18n.set(german);

Missing messages fall back to English. Runtime language changes update Domternal's UI without translating or changing the document. Domternal does not add a language selector; your application chooses when to pass a new configuration. See the localization guide for wrapper examples, partial catalogs, formatting, and custom translation resolvers.

In 1.4.0, message authors can mark additive definitions with optionalTranslation: true. CompleteMessages keeps existing unmarked messages required while allowing those new translations to use the built-in fallback. Use Required> to check a translation for every current message.

Version compatibility

Upgrade installed @domternal/* packages together to 1.7.0. Wrappers require core >=1.7.0 <2.0.0, and extensions require both core and pm as peers in that range. Core 1.7.0 requires pm >=1.7.0 <2.0.0 at runtime.

Version 1.7.0 adds annotateDocumentNotes for application-owned static previews. Pass a full-document snapshot to keep footnote and endnote labels consistent across rendered fragments, and optionally pass the editor's presentation service for translated headings and accessible reference labels. The helper changes presentation only; existing JSON and schema configuration remain unchanged. An explicit snapshot keeps missing or duplicate identities unresolved instead of inventing local numbers.

Version 1.6.0 introduced opt-in image transforms, document notes and table layout settings, plus compound and local PNG list labels. Enable the corresponding schema options on every collaborative writer before storing that content. The original ListLabel helpers keep their counter/text contract; use the additive ExtendedListLabel APIs for the new label kinds. That release also introduced createSchema and optional print resource preparation, with matching Core, Table and theme support for eligible multirow print headers. DOCX/PDF adapters for supported models live in the separate Pro Import and Pro Export packages; this Free release does not publish those adapters.

Version 1.5.1 fixed Paste Cleanup image byte accounting and configuration guidance.

Version 1.5.0 adds optional ListLabels, bounded Word stylesheet typography, literal block backgrounds and a formatting choice for each paste. Use matching Core and theme packages for block fills and image upload feedback. ListLabels is not part of StarterKit: enable the same extension on all collaborative writers before storing custom labels. Existing schemas remain unchanged when it is omitted.

The opt-in text contrast and optional translation definitions introduced in 1.4.0 remain available; the default contrast policy preserves authored colors. PasteCleanup, explicit list markers, content diagnostics and coordinated clipboard handling were introduced in 1.3.0; Core 1.2.0 lacks those APIs.

The migration requirements for content validation and transaction callbacks introduced in 1.3.0 still apply. Loading JSON normalizes unsupported heading levels, list markers and table spans, and removes links the configured URL policy refuses while keeping their text. Stored JSON, strict loaders and mixed-version collaborative documents may need migration. Review the 1.3.0 breaking changes and the Core migration guidance before upgrading; use onContentDiagnostic to observe repairs and normalizeContentAttributes for an explicit migration of a live document.

Packages

| Package | Description | | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | @domternal/core | Editor engine with built-in nodes and marks, optional document notes, list-label and headless schema helpers, toolbar controller and icons | | @domternal/theme | Light and dark themes with 150+ CSS custom properties | | @domternal/angular | Angular wrapper: 6 components (editor, toolbar, bubble menu, floating menu, emoji picker, notion color picker) | | @domternal/react | React 18+ wrapper: composable component, toolbar, bubble menu, floating menu, emoji picker, notion color picker, node views | | @domternal/vue | Vue 3.3+ wrapper: composable component, composables, toolbar, bubble menu, floating menu, emoji picker, notion color picker, node views | | @domternal/vanilla | Framework-free class-based wrapper for Astro, Svelte, Solid, plain HTML, and Web Components | | @domternal/pm | ProseMirror re-exports (state, view, model, transform, commands, keymap, history, tables, and more) | | @domternal/extension-block-controls | Notion-style block UX: block handle, context menu, drag-to-reorder, keyboard reorder, slash command, floating menu, smart paste (formerly @domternal/extension-block-menu) | | @domternal/extension-toc | Notion-style Table of Contents: floating outline, inline /toc block, scrollToHeading command | | @domternal/extension-table | Tables with merge, split, resize, cell styling, row/column controls and opt-in row/cell layout settings | | @domternal/extension-math | LaTeX math: inline and block equations with a pluggable renderer (KaTeX) | | @domternal/extension-markdown | GitHub-flavored Markdown import and export: markdown paste, insertMarkdown/setMarkdownContent, headless parser and serializer with fidelity warnings | | @domternal/extension-paste-cleanup | Opt-in Office HTML paste normalization, preserve/adapt formatting, and bounded diagnostics through the extension or standalone /html entry | | @domternal/extension-image | Images with paste/drop upload, URL input, XSS protection, bubble menu and opt-in crop, rotate and mirror geometry | | @domternal/extension-emoji | Emoji picker panel and :shortcode: autocomplete | | @domternal/extension-mention | @mention autocomplete with multi-trigger and async support | | @domternal/extension-details | Collapsible details/accordion blocks | | @domternal/extension-code-block-lowlight | Syntax-highlighted code blocks powered by lowlight |

The table above lists all 18 current MIT packages in this workspace, including @domternal/extension-paste-cleanup, introduced in 1.3.0. npm search may still show @domternal/extension-block-menu as a historical, deprecated 0.x entry. It is not an additional current package. Briefly published 1.0.x builds were withdrawn from the registry; import @domternal/extension-block-controls directly.

PasteCleanup normalizes pasted HTML, rebuilds lists from explicit Office list metadata, and keeps a bounded set of inherited inline formatting. Reviewed native captures qualify Word 16.113.3 for Mac copied in Safari 26.5.2, Chrome 154 and Firefox 155, and Google Docs web copied in Chrome 153 on macOS. Those captures were replayed through synthetic paste events; the current English regression fixtures are authored derivatives, not new native captures. Google Docs in Safari and Firefox, Word for Windows, Word on the web, LibreOffice and Collabora remain unqualified. See the support matrix for exact limits. DOCX file import is available separately in Domternal Pro.

See Packages & Bundle Size for a full breakdown of what each package includes and how tree-shaking works.

Domternal Pro

Domternal Pro adds the collaborative layer on top of these MIT packages, published as @domternal-pro/* on the public npm registry under a commercial license: real-time collaboration with live carets and presence, comments, version history, an AI assistant, columns, Word document import, Word and PDF export, and a self-hosted collaboration server.

Documentation

Full documentation, live playgrounds, and API reference at domternal.dev.

Contributing

See CONTRIBUTING.md for commit conventions, PR guidelines, and development setup.

pnpm install    # Install dependencies
pnpm build      # Build all packages
pnpm test       # Run tests
pnpm lint       # Run linter
pnpm typecheck  # Type check

Requires Node.js >= 22 and pnpm >= 10.

License

The source code is available under the MIT License. Use of the Domternal name and logo is governed by the Trademark Usage Policy.

Chat with me