57 Extensions · Light & Dark Theme · MIT License

The Rich Text Editor
Angular Deserves

Toolbar, bubble menu, tables, code blocks, image upload, and more. All included, all ready to use.

Or use the headless core to build your own UI, any framework.

npm i @domternal/core @domternal/angular @domternal/theme
Live Demo

Try it yourself

A fully interactive editor. Type, format, and explore every feature live.

Domternal in numbers
4,200+ Tests
57 Extensions
~116 KB gzipped (core + toolbar + bubble menu + theme)
100% TypeScript
MIT License
Developer Experience

Get started in minutes

A few lines of code is all you need

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();
});
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>';
}
Core Features

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 10 packages. Tables, images, emoji, mentions, details, syntax highlighting. Everything included.

Angular-First

5 components: editor, toolbar, bubble menu, floating menu, emoji picker. Signals, OnPush, ControlValueAccessor. Built for modern Angular.

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.

4,200+ Tests

2,675 unit tests across 92 files. 1,550 Playwright E2E tests across 34 specs. Every extension, mark, and node is tested.

Free Tables

Full table support,
Angular & 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
Explore Table Docs →
Feature Q1 Q2 Q3
Editor Core Released Stable Stable
Tables Released Stable Stable
Theme Light + Dark (Merged Cell)
Angular 5 Components Signals OnPush
Extension Ecosystem

Every extension you need

Batteries included: from basic formatting to advanced features.

Bold Italic Underline Strikethrough Code Link Subscript Superscript Highlight Text Color Bold Italic Underline Strikethrough Code Link Subscript Superscript Highlight Text Color
Font Family Font Size Line Height Clear Formatting Heading Paragraph Blockquote Code Block Syntax Highlighting Horizontal Rule Font Family Font Size Line Height Clear Formatting Heading Paragraph Blockquote Code Block Syntax Highlighting Horizontal Rule
Bullet List Ordered List Task List Table Image Emoji Mention Details History Text Align Typography Bullet List Ordered List Task List Table Image Emoji Mention Details History Text Align Typography
Placeholder Character Count Bubble Menu Floating Menu Dropcursor Gapcursor Trailing Node Invisible Characters Unique ID Starter Kit Focus Placeholder Character Count Bubble Menu Floating Menu Dropcursor Gapcursor Trailing Node Invisible Characters Unique ID Starter Kit Focus

23 nodes, 9 marks, 25 extensions across 10 packages. All MIT licensed.

View All Extensions →
Under the Hood

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 Support

Framework-agnostic core, Angular first

The core works with any framework. Angular components ship today. React and Vue coming soon.

Angular
Vanilla JS
React
Vue
Pricing

Simple, transparent pricing

Open source core, MIT licensed. Pro extensions coming soon for teams that need more.

Pro Coming Soon
Pricing TBA

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

Start building today

Open source core, MIT licensed. 57 extensions, full tables, built-in toolbar and theme. A feature-complete rich text editor for Angular.

Get Started → View on GitHub

Get notified when Pro launches

Leave your email and we'll let you know.