Getting Started
Pick your setup: Core for a headless editor you style yourself, Core + UI for a themed editor with toolbar and bubble menu out of the box, or Angular for ready-made components with auto-rendered toolbar and menus.
Installation
Section titled “Installation”pnpm add @domternal/corenpm install @domternal/coreyarn add @domternal/coreCreate Your First Editor
Section titled “Create Your First Editor”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>Bold</strong>, <em>Italic</em> and <u>Underline</u>!</p>',});<div id="editor"></div>Import only what you need for full control and zero bloat. Use StarterKit instead for a batteries-included setup with headings, lists, code blocks, history, and more.
Live Playground
Section titled “Live Playground”Select text and press Mod+B for bold, Mod+I for italic, or Mod+U for underline.
Next Steps
Section titled “Next Steps”Now that your editor is running, explore the rest of the toolkit:
- StarterKit - use
StarterKitfor a batteries-included setup with headings, lists, code blocks, history, and more - Extensions - add tables, images, emoji, mentions, and syntax-highlighted code blocks via standalone packages
- Theming - style your editor with CSS or use the ready-made
@domternal/theme - Editor API - chain commands, listen to events, and read or update content programmatically
Installation
Section titled “Installation”pnpm add @domternal/core @domternal/themenpm install @domternal/core @domternal/themeyarn add @domternal/core @domternal/themeCreate Your First Editor
Section titled “Create Your First Editor”import { Editor, StarterKit, defaultIcons } from '@domternal/core';import '@domternal/theme';
const editorEl = document.getElementById('editor')!;
// Toolbarconst 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);
// Editorconst editor = new Editor({ element: editorEl, extensions: [StarterKit], content: '<p>Hello world</p>',});
// Toggle marks on click (event delegation)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();});
// Active state synceditor.on('transaction', () => { toolbar.querySelectorAll<HTMLButtonElement>('[data-mark]').forEach((btn) => { btn.classList.toggle('dm-toolbar-button--active', editor.isActive(btn.dataset.mark!)); });});<div id="editor" class="dm-editor"></div>StarterKit provides paragraphs, headings, lists, blockquotes, code blocks, task lists, inline formatting, keyboard shortcuts, and undo/redo. The @domternal/theme package adds editor styles, a toolbar layout, and 45 built-in icons via defaultIcons.
For full control, skip StarterKit and import only the extensions you need.
Live Playground
Section titled “Live Playground”StarterKit Contents
Section titled “StarterKit Contents”Every extension in the kit can be disabled with false or configured with options:
StarterKit.configure({ codeBlock: false, // disable an extension heading: { levels: [1, 2, 3, 4] }, // limit heading levels history: { depth: 50 }, // configure undo stack link: { openOnClick: false }, // keep links non-clickable while editing linkPopover: false, // disable the built-in link popover})The full list of bundled extensions:
| Category | Included |
|---|---|
| Nodes | Document, Text, Paragraph, Heading, Blockquote, CodeBlock, BulletList, OrderedList, ListItem, TaskList, TaskItem, HorizontalRule, HardBreak |
| Marks | Bold, Italic, Underline, Strike, Code, Link |
| Behaviors | BaseKeymap, History, Dropcursor, Gapcursor, TrailingNode, ListKeymap, LinkPopover |
Next Steps
Section titled “Next Steps”Now that your editor is running, explore the rest of the toolkit:
- StarterKit - see above for the full list of bundled extensions and how to configure them
- Extensions - add tables, images, emoji, mentions, and syntax-highlighted code blocks via standalone packages
- Theming - customize colors, spacing, and fonts with 70+ CSS custom properties on
.dm-editor - Editor API - chain commands, listen to events, and read or update content programmatically
Installation
Section titled “Installation”pnpm add @domternal/core @domternal/theme @domternal/angularnpm install @domternal/core @domternal/theme @domternal/angularyarn add @domternal/core @domternal/theme @domternal/angularCreate Your First Editor
Section titled “Create Your First Editor”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], templateUrl: './editor.html',})export class EditorComponent { editor = signal<Editor | null>(null); extensions = [StarterKit, BubbleMenu]; content = '<p>Hello from Angular!</p>';}@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" />}Add the theme to your global stylesheet to load editor and toolbar styles:
@use '@domternal/theme';The toolbar and bubble menu components auto-render buttons based on the extensions you provide. No manual button wiring needed. Under the hood it renders the same editor:
Live Playground
Section titled “Live Playground”What You Get Out of the Box
Section titled “What You Get Out of the Box”The Angular components handle everything automatically:
<domternal-toolbar>renders buttons based on the extensions you provide, with active and disabled states<domternal-bubble-menu>appears on text selection with contextual formatting options- Signals drive reactivity, no manual subscription management needed
- Both toolbar and bubble menu support custom layouts so you can choose which buttons to show and in what order
StarterKit Contents
Section titled “StarterKit Contents”Every extension in the kit can be disabled with false or configured with options:
StarterKit.configure({ codeBlock: false, // disable an extension heading: { levels: [1, 2, 3, 4] }, // limit heading levels history: { depth: 50 }, // configure undo stack link: { openOnClick: false }, // keep links non-clickable while editing linkPopover: false, // disable the built-in link popover})The full list of bundled extensions:
| Category | Included |
|---|---|
| Nodes | Document, Text, Paragraph, Heading, Blockquote, CodeBlock, BulletList, OrderedList, ListItem, TaskList, TaskItem, HorizontalRule, HardBreak |
| Marks | Bold, Italic, Underline, Strike, Code, Link |
| Behaviors | BaseKeymap, History, Dropcursor, Gapcursor, TrailingNode, ListKeymap, LinkPopover |
Next Steps
Section titled “Next Steps”Now that your editor is running, explore the rest of the toolkit:
- StarterKit - see above for the full list of bundled extensions and how to configure them
- Extensions - add tables, images, emoji, mentions, and syntax-highlighted code blocks via standalone packages
- Theming - customize the look with 70+ CSS custom properties
- Reactive Forms - bind editor content with
formControlNameorngModel - Editor API - chain commands, listen to events, and read or update content programmatically