Skip to content

Ordered List

The OrderedList node provides a block-level numbered list container (<ol>). It supports a start attribute for custom numbering, a markdown-style input rule (number + . + space), a keyboard shortcut (Mod-Shift-7), and automatic inclusion of the ListItem node and ListKeymap extension for Tab/Shift-Tab indentation.

Use OrderedList when you need:

  • Numbered list items with 1. markdown shortcut and Cmd+Shift+7
  • A custom start attribute (lists that begin at 5, 10, etc.)
  • Nestable list items with Tab to indent and Shift+Tab to outdent

Skip it if:

  • You need unordered items (use BulletList instead)
  • You need checkbox to-do behavior (use TaskList instead)

Type a number followed by . and space (e.g. 1. ) at the start of a line to create an ordered list. Use Tab to indent and Shift-Tab to outdent.

Click to try it out

OrderedList is included in StarterKit. If you are building a custom setup without StarterKit, add it manually:

import { Document, Text, Paragraph, OrderedList } from '@domternal/core';
import { DomternalEditor } from '@domternal/vanilla';
const dm = new DomternalEditor(document.getElementById('editor')!, {
extensions: [Document, Text, Paragraph, OrderedList],
content: '<ol><li><p>First item</p></li><li><p>Second item</p></li></ol>',
});
PropertyValue
ProseMirror nameorderedList
TypeNode
Groupblock list
ContentlistItem+ (one or more list items)
HTML tag<ol>

The list group allows ProseMirror to identify this node as a list container, which is used by list-related commands like toggleList.

OptionTypeDefaultDescription
HTMLAttributesRecord<string, unknown>{}HTML attributes added to the <ol> element
itemTypeNamestring'listItem'Name of the list item node type used by toggleList
import { OrderedList } from '@domternal/core';
const CustomOrderedList = OrderedList.configure({
HTMLAttributes: { class: 'my-numbered-list' },
});
AttributeTypeDefaultDescription
startnumber1The starting number for the list

The start attribute is parsed from the <ol> element’s start HTML attribute and clamped to a finite integer >= 1, so malformed values (e.g. start="abc") normalize to 1 instead of leaking NaN/null into the document. When the value is 1 (the default), the start attribute is omitted from the rendered HTML. For any other value, it is rendered as <ol start="5">.

Typing 5. at the start of a line creates an ordered list starting at 5. The start number is extracted from the input rule match.

// Set content with a list starting at 3
editor.setContent('<ol start="3"><li><p>Third</p></li><li><p>Fourth</p></li></ol>');
CommandDescription
toggleOrderedList()Toggle the whole list between ordered list and paragraph
turnIntoOrderedList()Convert only the cursor’s item to an ordered list (Notion per-item turn-into)
// Toggle ordered list on/off
editor.commands.toggleOrderedList();
// With chaining
editor.chain().focus().toggleOrderedList().run();

toggleOrderedList wraps the selected blocks in an <ol> with <li> items. If the selection is already inside an ordered list, it unwraps it back to paragraphs. If the selection is inside a different list type (bullet list, task list), it converts it to an ordered list.

Whole-list toggle vs per-item turn-into (v0.9.0)

Section titled “Whole-list toggle vs per-item turn-into (v0.9.0)”

The two commands differ in scope when the cursor sits inside a list of another kind:

  • toggleOrderedList() converts the whole list. Used by the toolbar button and the Mod-Shift-7 shortcut, preserving classic-editor semantics.
  • turnIntoOrderedList() converts only the cursor’s item and splits the run, leaving its siblings untouched (Notion-style). This is what the slash command’s “Numbered list” entry and the block menu’s “Turn into” submenu use. Internally it calls toggleList(name, itemTypeName, undefined, { perItem: true }).
ShortcutCommand
Mod-Shift-7toggleOrderedList()
EnterSplit list item at cursor, or lift out of list if empty
TabIndent list item (sink)
Shift-TabOutdent list item (lift)
BackspaceLift list item when at the start of an empty item

The Enter, Tab, Shift-Tab, and Backspace shortcuts are provided by the ListItem node and ListKeymap extension, which are automatically included when you add OrderedList.

The list-item children-zone is now strictly paragraph block* (see List Item migration). Several Notion-style behaviors follow:

  • Backspace on an empty paragraph immediately after a list: Deletes the paragraph and places the caret at the end of the last item.
  • Backspace on an empty paragraph between two same-type lists: Joins the two lists back into one.
  • toggleList in a children-zone paragraph: Wraps that paragraph in a FRESH list (does not convert the ancestor list type).
  • Tab on a top-level paragraph immediately after a list: With the opt-in ListIndent extension (off by default), indents the paragraph INTO the previous list as a nested child. Without it, Tab moves focus to the next field as usual.
InputResult
1. + spaceOrdered list starting at 1
5. + spaceOrdered list starting at 5
42. + spaceOrdered list starting at 42

Type any number followed by . and space at the start of a new line. The line wraps in an ordered list with the start attribute set to the typed number. These input rules only fire outside of existing lists - typing 1. inside a list item inserts the characters as plain text. To nest lists, use Tab to indent a list item.

The rule joins adjacent ordered lists on both sides: creating an item on a line that sits between two ordered lists merges all of them into a single list, rather than leaving the following list as a separate sibling.

The regex pattern is /^(\d+)\.\s$/, which captures the number for the start attribute.

OrderedList registers a button in the toolbar with the name orderedList in group lists at priority 190.

ItemCommandIconShortcut
Ordered ListtoggleOrderedListlistNumbersMod-Shift-7

OrderedList automatically includes these extensions via addExtensions():

ExtensionDescription
ListItemThe <li> node used inside the list
ListKeymapTab/Shift-Tab indentation and Backspace handling (included by ListItem)

This means adding OrderedList to your extensions array is sufficient. You don’t need to add ListItem or ListKeymap separately.

{
"type": "orderedList",
"attrs": { "start": 1 },
"content": [
{
"type": "listItem",
"content": [
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "First item" }
]
}
]
},
{
"type": "listItem",
"content": [
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "Second item" }
]
}
]
}
]
}

An ordered list starting at 5:

{
"type": "orderedList",
"attrs": { "start": 5 },
"content": [
{
"type": "listItem",
"content": [
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "Fifth item" }
]
}
]
}
]
}

@domternal/core - OrderedList.ts