Docs Blog Tutorials ProSoon Contact
Follow on X GitHub

Every surface of the editor

Most of what an editor does only shows up once you interact with it. This page collects every user interface surface Domternal ships, in both the classic and the Notion-style preset, with a link to the reference documentation for each. Everything here is part of the free, MIT-licensed packages.

Classic mode
The classic Domternal editor with the full toolbar, showing formatted text, a nested list, a task list and a comparison table The classic Domternal editor with the full toolbar, showing formatted text, a nested list, a task list and a comparison table
Classic preset, full toolbar.
Notion mode
The same editor in Notion mode, with no toolbar and a centred document column The same editor in Notion mode, with no toolbar and a centred document column
Notion preset, one class on the editor.

Prefer to drive it yourself? Open the live playground or read the getting started guide.

Formatting

Marks are the same commands wherever you run them from. What changes is the surface: a strip that is always there, a menu that follows the selection, or a shortcut that opens a popover exactly where the caret is.

Toolbar

The toolbar is not a fixed list. Each extension contributes its own items through addToolbarItems(), so enabling the table package adds table controls and nothing else has to know. Groups, separators and dropdowns are assembled from whatever is registered, and every item exposes its active and disabled state to the button that renders it.

Toolbar
The Domternal toolbar showing text style, colour, font size, heading, list, quote, code, table and emoji controls above a document The Domternal toolbar showing text style, colour, font size, heading, list, quote, code, table and emoji controls above a document
Heading dropdown
The heading dropdown open from the toolbar, listing paragraph and heading levels one through six The heading dropdown open from the toolbar, listing paragraph and heading levels one through six

Bubble menu

Select text and a compact menu follows the selection. It is positioned with @floating-ui/dom against an absolutely positioned host inside the editor, so scrolling costs no JavaScript at all: the compositor moves it. Which buttons appear is a plain array, so a comment or AI action drops in next to bold.

Bubble menu
A floating bubble menu with bold, italic, underline, strike and code buttons, appearing above a selected phrase A floating bubble menu with bold, italic, underline, strike and code buttons, appearing above a selected phrase

Colour and highlight

Two surfaces over one set of tokens. The toolbar opens a grid palette for text colour and highlight with the active swatch marked, and the bubble menu opens the Notion-style panel that covers text and background together. Both write the same text-style mark, so a colour set in one reads as active in the other.

Toolbar palette
A grid colour palette open from the toolbar, with rows of text colour swatches and a reset option A grid colour palette open from the toolbar, with rows of text colour swatches and a reset option
Bubble menu panel
The Notion-style colour panel open from the bubble menu, with a text colour list above a background colour list The Notion-style colour panel open from the bubble menu, with a text colour list above a background colour list

Blocks and structure

Everything in the document is a block, and every block gets the same grip, the same menu and the same drag behaviour, whether it is a paragraph or a table.

Block handle

Hover a block and a grip appears in the gutter beside it, with a plus button to insert below. Dragging reorders, and dragging onto the edge of a list item nests instead. The handle knows which node types accept which children, so it will not let you drop a heading inside a table cell.

Block handle
A drag handle and plus button revealed in the left gutter next to a paragraph A drag handle and plus button revealed in the left gutter next to a paragraph
Notion mode

Block menu

Clicking the handle opens the block menu: delete, duplicate, copy a link straight to that block, set a text or background colour, or turn the block into another type. Turn into preserves the text and replaces the node around it, so a paragraph becomes a heading without retyping anything.

Block menu
The block context menu open, showing Delete, Duplicate and Copy link, a two-row colour palette, and Turn into options The block context menu open, showing Delete, Duplicate and Copy link, a two-row colour palette, and Turn into options

Details and toggles

A disclosure block with an editable summary row and a collapsible body that accepts any block content: lists, code, even another toggle. The chevron is a real button with aria-expanded and aria-controls pointing at the body, so the open state is announced rather than left for a screen reader to infer.

Toggle block
An expanded toggle block with a bold summary row, a chevron on the right, and a paragraph of body text inside it An expanded toggle block with a bold summary row, a chevron on the right, and a paragraph of body text inside it

Task lists

Checkboxes are a node view rather than a character, so clicking one dispatches a transaction and the checked state lives in the document. They nest with Tab like any other list and mix freely with bullets and ordered items at any depth, and Backspace at the start of the first item lifts out instead of merging upward.

Insert menus

Three ways to put a new block in the document, sharing one item registry: whatever an extension registers appears in all of them at once.

Slash menu

Type a slash on an empty line and the insert menu opens where the caret is. It filters as you type, groups results, and shows each item with its icon, description and shortcut. Arrow keys move, Enter inserts, Escape closes and leaves the slash you typed as ordinary text.

Slash menu
The slash command menu open on an empty line, listing block types with icons, labels, descriptions and keyboard shortcuts The slash command menu open on an empty line, listing block types with icons, labels, descriptions and keyboard shortcuts
Notion mode

Floating menu

The same items as the slash menu, opened from the plus button in the gutter instead of the keyboard. It keeps the group labels and shortcut hints that a filtered slash query hides, which makes it the better way to find out what is insertable in the first place rather than to insert something you already know.

Floating menu
The floating insert menu open beside a block, with group headings and rows carrying an icon, a label and a shortcut The floating insert menu open beside a block, with group headings and rows carrying an icon, a label and a shortcut

Emoji

The picker offers search, nine category tabs and a keyboard-navigable grid. Typing a colon opens the same set inline as a suggestion list, and both shortcodes and typed emoticons convert through input rules, so three different routes reach the same inline node.

Emoji picker
The emoji picker open from the toolbar, with a search field, category tabs and a grid of emoji The emoji picker open from the toolbar, with a search field, category tabs and a grid of emoji
Inline suggestion
An inline emoji suggestion list open mid-sentence after typing a colon, each row showing the glyph next to its name An inline emoji suggestion list open mid-sentence after typing a colon, each row showing the glyph next to its name

Content types

The nodes that are more than text. Each is a real ProseMirror node with its own schema, commands and node view, not markup pasted into a paragraph and hoped for.

Tables

Tables are a first-class node with eighteen commands. Row, column and corner grips appear on hover: the corner opens a cell toolbar with alignment, cell colour and a header toggle, and each axis grip opens the insert, delete, merge and split actions that apply to it. Columns resize by dragging their borders.

Table
A three column table in the editor with a header row and bordered cells A three column table in the editor with a header row and bordered cells
Cell toolbar
A table with a cell selected, its corner grip open into a toolbar carrying colour, alignment, insert and header controls A table with a cell selected, its corner grip open into a toolbar carrying colour, alignment, insert and header controls

Images

Insert from the slash menu and a popover asks for a URL and alt text, with a Browse button for a local file. Once placed, four corner handles resize it live, and the bubble menu switches to image actions: inline, float left, centre, float right, edit the alt text, delete. Pasting or dropping a file uploads it behind a placeholder.

Image popover
An image popover with URL and alt text fields, a Browse button for a local file, and an Apply button An image popover with URL and alt text fields, a Browse button for a local file, and an Apply button

Math

Inline equations sit in the run of text and block equations stand on their own line, both rendered through a pluggable renderer with KaTeX as the default. Click one and a popover opens with the LaTeX in an editable field and a live preview beneath it, so the result is visible before you commit to it.

Inline and block math
A paragraph with an inline rendered equation in the run of text, above a centred block equation on its own line A paragraph with an inline rendered equation in the run of text, above a centred block equation on its own line
Equation editor
A selected block equation with an editing popover under it, holding the raw LaTeX in a text area above a live rendered preview A selected block equation with an editing popover under it, holding the raw LaTeX in a text area above a live rendered preview

Code blocks

Code blocks highlight through lowlight, with the common language set rather than the full registry so the chunk stays small. Language is stored on the node, Tab indents inside the block instead of leaving it, and pasting a fenced Markdown block creates one directly.

Code block
A syntax-highlighted TypeScript code block inside the editor A syntax-highlighted TypeScript code block inside the editor

Markdown

Markdown is a two-way door. Pasting a document as plain text converts it into real blocks, and the same serializer turns the document back into GitHub-flavored Markdown, with a one-call helper that hands the reader a .md file. A round trip is lossless for everything the schema can express.

Classic mode

Craft

The parts that never make a feature list and decide whether the editor feels finished.

Table of contents

A tick per heading sits at the edge of the document and expands into a full outline on hover, tracking the scroll position to mark the current section. The same extension inserts an in-document outline block, which updates as you write and links to each heading.

Outline rail
A slim vertical outline rail at the edge of the document, expanded into a card listing every heading A slim vertical outline rail at the edge of the document, expanded into a card listing every heading
In-document outline
An in-document table of contents block listing the headings of the page, with the current section highlighted An in-document table of contents block listing the headings of the page, with the current section highlighted

Notion mode

One class on the editor. It drops the toolbar, narrows the column, moves the block handles out into the gutter and upgrades the bubble menu to carry alignment and inline maths. Nothing underneath changes: the schema, the commands and the extensions are the ones the classic preset uses.

Notion mode
The bubble menu in Notion mode over a borderless centred document column, carrying alignment and inline maths alongside the mark buttons The bubble menu in Notion mode over a borderless centred document column, carrying alignment and inline maths alongside the mark buttons

Theming

Every screenshot on this page is here twice, once per theme, and the toggle in the corner is what swaps them. The editor works the same way: colours, radii and spacing are all CSS custom properties on the editor root, so a handful of overrides is a brand, and light, dark and auto ship as they are.

Keyboard and accessibility

Menus carry role=menu with roving tabindex and aria-activedescendant, popovers manage their own focus, and an aria-live region announces what a transaction changed. Every pointer gesture has a keyboard twin: Mod-Shift with an arrow key moves a block without a pointer, and Tab nests a list item.

Try it in your own project

Everything on this page is in the free packages. Install takes one command.