Getting Started
Pick your setup: Vanilla JS/TS for a themed editor with toolbar and bubble menu out of the box, Angular, React, or Vue for ready-made components with auto-rendered toolbar and menus, or Headless for a bare editor you style yourself.
-
Installation
Section titled “Installation”Terminal window pnpm add @domternal/core @domternal/themeTerminal window npm install @domternal/core @domternal/themeTerminal window yarn add @domternal/core @domternal/theme -
Create 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>StarterKitprovides paragraphs, headings, lists, blockquotes, code blocks, task lists, inline formatting, keyboard shortcuts, and undo/redo. The@domternal/themepackage adds editor styles, a toolbar layout, and 45 built-in icons viadefaultIcons.For full control, skip
StarterKitand import only the extensions you need.
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, SelectionDecoration |
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
- StackBlitz Example - a full working vanilla editor with all extensions you can edit in the browser
-
Installation
Section titled “Installation”Terminal window pnpm add @domternal/core @domternal/theme @domternal/angularTerminal window npm install @domternal/core @domternal/theme @domternal/angularTerminal window yarn add @domternal/core @domternal/theme @domternal/angular -
Create 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
Section titled “Add the Theme”Add the theme to your global stylesheet to load editor and toolbar styles:
styles.scss @use '@domternal/theme';The toolbar and bubble menu components auto-render buttons based on the extensions you provide. No manual button wiring needed.
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, SelectionDecoration |
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
- StackBlitz Example - a full working Angular editor with all extensions you can edit in the browser
-
Installation
Section titled “Installation”Terminal window pnpm add @domternal/core @domternal/theme @domternal/reactTerminal window npm install @domternal/core @domternal/theme @domternal/reactTerminal window yarn add @domternal/core @domternal/theme @domternal/react -
Create Your First Editor
Section titled “Create Your First Editor”import { Domternal } from '@domternal/react';import { StarterKit, BubbleMenu } from '@domternal/core';export default function Editor() {return (<Domternalextensions={[StarterKit, BubbleMenu]}content="<p>Hello from React!</p>"><Domternal.Toolbar /><Domternal.Content /><Domternal.BubbleMenu /></Domternal>);}Domternalwraps your editor with a context provider. The subcomponents (Toolbar,Content,BubbleMenu) automatically connect to the editor instance. No manual wiring needed. -
Add the Theme
Section titled “Add the Theme”Import the theme in your root CSS or entry file to load editor and toolbar styles:
index.css @import '@domternal/theme';The toolbar and bubble menu components auto-render buttons based on the extensions you provide. No manual button wiring needed.
What You Get Out of the Box
Section titled “What You Get Out of the Box”The React components handle everything automatically:
<Domternal.Toolbar />renders buttons based on the extensions you provide, with active and disabled states<Domternal.BubbleMenu />appears on text selection with contextual formatting optionsuseEditorhook for lower-level control when you need custom behavioruseEditorStatehook with selector support for granular re-renders- 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, SelectionDecoration |
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
- Hooks - use
useEditoranduseEditorStatefor full control over editor state - Editor API - chain commands, listen to events, and read or update content programmatically
- StackBlitz Example - a full working React editor with all extensions you can edit in the browser
-
Installation
Section titled “Installation”Terminal window pnpm add @domternal/core @domternal/theme @domternal/vueTerminal window npm install @domternal/core @domternal/theme @domternal/vueTerminal window yarn add @domternal/core @domternal/theme @domternal/vue -
Create Your First Editor
Section titled “Create Your First Editor”<script setup lang="ts">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>Domternalwraps your editor with a provide/inject context. The subcomponents (Toolbar,Content,BubbleMenu) automatically connect to the editor instance. No manual wiring needed. -
Add the Theme
Section titled “Add the Theme”Import the theme in your main entry file or component to load editor and toolbar styles:
main.ts import '@domternal/theme';The toolbar and bubble menu components auto-render buttons based on the extensions you provide. No manual button wiring needed.
What You Get Out of the Box
Section titled “What You Get Out of the Box”The Vue components handle everything automatically:
<Domternal.Toolbar />renders buttons based on the extensions you provide, with active and disabled states<Domternal.BubbleMenu />appears on text selection with contextual formatting optionsuseEditorcomposable for lower-level control when you need custom behavioruseEditorStatecomposable with selector support for granular reactivity- 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, SelectionDecoration |
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
- Composables - use
useEditoranduseEditorStatefor full control over editor state - Editor API - chain commands, listen to events, and read or update content programmatically
- StackBlitz Example - a full working Vue editor with all extensions you can edit in the browser
Select text and press Mod+B for bold, Mod+I for italic, or Mod+U for underline.
-
Installation
Section titled “Installation”Terminal window pnpm add @domternal/coreTerminal window npm install @domternal/coreTerminal window yarn add @domternal/core -
Create 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
StarterKitinstead for a batteries-included setup with headings, lists, code blocks, history, and more.
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