The Rich Text Editor
Vue Deserves
Composable components, composables, toolbar, bubble menu, tables, and more. Import only what you need, your bundler tree-shakes the rest.
Angular and React components also available. Or use the headless core with any framework.
npm i @domternal/core @domternal/vue @domternal/theme Try it yourself
Get started in minutes
A few lines of code is all you need
<script setup> import { Domternal } from '@domternal/vue'; import { StarterKit, BubbleMenu } from '@domternal/core'; const extensions = [StarterKit, BubbleMenu]; </script> <template> <Domternal :extensions="extensions" content="<p>Hello from Vue!</p>" > <Domternal.Toolbar /> <Domternal.Content /> <Domternal.BubbleMenu /> </Domternal> </template>
import { Component, signal } from '@angular/core'; import { DomternalEditorComponent, DomternalToolbarComponent, DomternalBubbleMenuComponent, } from '@domternal/angular'; import { Editor, StarterKit, BubbleMenu } from '@domternal/core'; @Component({ selector: 'app-editor', imports: [DomternalEditorComponent, DomternalToolbarComponent, DomternalBubbleMenuComponent], template: ` @if (editor(); as ed) { <domternal-toolbar [editor]="ed" /> } <domternal-editor [extensions]="extensions" [content]="content" (editorCreated)="editor.set($event)" /> @if (editor(); as ed) { <domternal-bubble-menu [editor]="ed" /> } ` }) export class EditorComponent { editor = signal<Editor | null>(null); extensions = [StarterKit, BubbleMenu]; content = '<p>Hello from Angular!</p>'; }
import { Domternal } from '@domternal/react'; import { StarterKit, BubbleMenu } from '@domternal/core'; export default function Editor() { return ( <Domternal extensions={[StarterKit, BubbleMenu]} content="<p>Hello from React!</p>" > <Domternal.Toolbar /> <Domternal.Content /> <Domternal.BubbleMenu /> </Domternal> ); }
import { Editor, Document, Text, Paragraph, Bold, Italic, Underline, } from '@domternal/core'; new Editor({ element: document.getElementById('editor')!, extensions: [Document, Text, Paragraph, Bold, Italic, Underline], content: '<p>Hello <strong>Bold</strong>, <em>Italic</em> and <u>Underline</u>!</p>', });
import { Editor, StarterKit, defaultIcons } from '@domternal/core'; import '@domternal/theme'; const editorEl = document.getElementById('editor')!; // Toolbar const toolbar = document.createElement('div'); toolbar.className = 'dm-toolbar'; toolbar.innerHTML = `<div class="dm-toolbar-group"> <button class="dm-toolbar-button" data-mark="bold">${defaultIcons.textB}</button> <button class="dm-toolbar-button" data-mark="italic">${defaultIcons.textItalic}</button> <button class="dm-toolbar-button" data-mark="underline">${defaultIcons.textUnderline}</button> </div>`; editorEl.before(toolbar); // Editor const editor = new Editor({ element: editorEl, extensions: [StarterKit], content: '<p>Hello world</p>', }); // Toggle marks on click toolbar.addEventListener('click', (e) => { const btn = (e.target as Element).closest<HTMLButtonElement>('[data-mark]'); if (!btn) return; editor.chain().focus().toggleMark(btn.dataset.mark!).run(); });
Everything you need to build
rich editing experiences
A complete editor framework with full control over every aspect of your editor.
57 Built-in Extensions
23 nodes, 9 marks, 25 extensions across 12 packages. Tables, images, emoji, mentions, details, syntax highlighting. Everything included.
Vue Components & Composables
Composable <Domternal> component with toolbar, bubble menu, floating menu, emoji picker. useEditor and useEditorState composables. Custom node views via VueNodeViewRenderer.
Built-in Toolbar & Theme
Every extension declares toolbar items via addToolbarItems(). 45 Phosphor icons included. Light & dark theme with CSS custom properties. Ready to customize.
Styled HTML Export
getHTML({ styled: true }) produces inline CSS ready for email clients, CMS, and Google Docs. Customizable styles for tables, blockquotes, code blocks, and more.
Markdown-Style Shortcuts
Type ## for heading, > for blockquote, - for list, **bold**, ==highlight==, --- for rule. Every extension registers its own input rules.
8,500+ Tests
2,677 unit tests across 92 files. 5,800+ Playwright E2E tests across 120+ specs. Every extension, mark, and node is tested.
Full table support,
Vue & Vanilla JS
- Cell merge & split (colspan/rowspan)
- 3 resize modes: neighbor, independent, redistribute
- constrainToContainer: lock or free table width
- Cell background, alignment, vertical align
- Export-ready: percent, pixel, or no column widths
- Floating cell toolbar on selection
- 18 table commands, 400+ tests
| Feature | Q1 | Q2 | Q3 |
|---|---|---|---|
| Editor Core | Released | Stable | Stable |
| Tables | Released | Stable | Stable |
| Theme | Light + Dark (Merged Cell) | ||
| Angular | 5 Components | Signals | OnPush |
Every extension you need
Batteries included: from basic formatting to advanced features.
57 total: 23 nodes, 9 marks, 25 extensions across 12 packages. All MIT licensed.
View All Packages →Built for production
Architecture decisions that make the difference at scale.
Schema Conflict Detection
Duplicate extension names throw a clear error at startup. No mysterious production bugs from silent overwrites.
Extension Composability
create() → configure() → extend() with this.parent?.() to call the base version. Override any hook while preserving parent behavior. Fully typed.
Fluent Command API
editor.chain().focus().toggleBold().run() chains commands on a shared transaction. editor.can().toggleBold() dry-runs without side effects. Fully typed.
XSS-Hardened Images
Blocks javascript:, vbscript:, file: protocols across four layers: parseHTML, renderHTML, commands, and input rules.
Global Attribute Injection
addGlobalAttributes() lets extensions inject attributes into node types they don't own. TextAlign, TextColor, FontSize, Highlight, and UniqueID all use this pattern. Zero coupling.
Zero-Jitter Floating UI
All floating elements use position: absolute inside the editor with @floating-ui/dom. CSS compositor handles scroll. Zero JS during scroll events.
SSR Ready
Server-side rendering via linkedom. Generate HTML on the server without a browser. Works with Angular Universal, Astro, and any Node.js environment.
Framework-agnostic core, Vue components included
The core works with any framework. Vue, Angular, and React components ship today.
Simple, transparent pricing
Open source core, MIT licensed. Pro extensions coming soon for teams that need more.
- Complete editor engine
- Vue components & composables (editor, toolbar, menus)
- Full tables: merge, resize, styling
- 57 extensions included
- Built-in toolbar & theme (light + dark)
- Image upload, emoji picker & mentions
- Angular & React components also available
Everything in Open Source, plus:
- Real-time collaboration (Yjs/CRDT)
- Inline comments & threads
- Track changes & revision history
- PDF / Word / Markdown export
- AI writing assistant
- Priority support & SLA
- ··· And more planned