List Item
The ListItem node represents an individual <li> element inside a BulletList or OrderedList. It handles Enter key splitting (creating new items or exiting the list), and automatically includes the ListKeymap extension for Tab/Shift-Tab indentation.
You don’t need to add ListItem manually. It is automatically included when you add BulletList or OrderedList via their addExtensions(). If you are using StarterKit, ListItem is already included.
import { Editor, Document, Text, Paragraph, BulletList, OrderedList } from '@domternal/core';
const editor = new Editor({ element: document.getElementById('editor')!, extensions: [Document, Text, Paragraph, BulletList, OrderedList], content: '<ul><li><p>First item</p></li><li><p>Second item</p></li></ul>',});import { Component, signal } from '@angular/core';import { DomternalEditorComponent } from '@domternal/angular';import { Editor, Document, Text, Paragraph, BulletList, OrderedList } from '@domternal/core';
@Component({ selector: 'app-editor', imports: [DomternalEditorComponent], template: ` <domternal-editor [extensions]="extensions" [content]="content" (editorCreated)="editor.set($event)" /> `,})export class EditorComponent { editor = signal<Editor | null>(null); extensions = [Document, Text, Paragraph, BulletList, OrderedList]; content = '<ul><li><p>First item</p></li><li><p>Second item</p></li></ul>';}import { Domternal } from '@domternal/react';import { Document, Text, Paragraph, BulletList, OrderedList } from '@domternal/core';
export default function Editor() { return ( <Domternal extensions={[Document, Text, Paragraph, BulletList, OrderedList]} content="<ul><li><p>First item</p></li><li><p>Second item</p></li></ul>" > <Domternal.Content /> </Domternal> );}ListItem is auto-included by BulletList and OrderedList. It has no commands of its own. List manipulation is done through the parent list commands:
// Create a bullet listeditor.commands.toggleBulletList();
// Create an ordered listeditor.commands.toggleOrderedList();
// ListItem handles Enter splitting and Tab/Shift-Tab// indentation automatically via ListKeymapSchema
Section titled “Schema”| Property | Value |
|---|---|
| ProseMirror name | listItem |
| Type | Node |
| Group | None (used as content of list nodes) |
| Content | block+ (one or more block nodes) |
| Defining | Yes |
| HTML tag | <li> |
The content expression block+ means a list item can contain paragraphs, headings, code blocks, nested lists, and other block-level nodes.
The defining property means that when you select a list item and paste content over it, the replacement keeps the list item wrapper.
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
HTMLAttributes | Record<string, unknown> | {} | HTML attributes added to the <li> element |
Custom HTML attributes
Section titled “Custom HTML attributes”import { ListItem } from '@domternal/core';
const CustomListItem = ListItem.configure({ HTMLAttributes: { class: 'my-list-item' },});Keyboard shortcuts
Section titled “Keyboard shortcuts”| Shortcut | Behavior |
|---|---|
Enter | Split list item at cursor position |
Enter (empty item) | Lift content out of the list (exit the list) |
Tab | Indent list item (sink into nested list) |
Shift-Tab | Outdent list item (lift out of nested list) |
Backspace | Lift list item when at the start of an empty item |
Enter behavior
Section titled “Enter behavior”The Enter key has context-dependent behavior:
- Non-empty item, cursor in middle: Splits the list item at the cursor, creating a new item with the text after the cursor.
- Non-empty item, cursor at end: Creates a new empty list item below.
- Empty item: Lifts the content out of the list. If the item is the last one, pressing Enter on an empty item exits the list and creates a paragraph below.
- Empty item inside a nested list within a task item: Escapes to the parent task level by creating a new task item, rather than leaving a bare paragraph.
Tab/Shift-Tab
Section titled “Tab/Shift-Tab”Tab and Shift-Tab are provided by the ListKeymap extension (automatically included). Tab sinks the current item into a nested list under the previous sibling, while Shift-Tab lifts it out one level.
Included extensions
Section titled “Included extensions”ListItem automatically includes the ListKeymap extension via addExtensions():
| Extension | Description |
|---|---|
| ListKeymap | Tab/Shift-Tab indentation and Backspace handling |
JSON representation
Section titled “JSON representation”A list item always wraps its content in block nodes:
{ "type": "listItem", "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "List item text" } ] } ]}A list item with a nested list:
{ "type": "listItem", "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "Parent item" } ] }, { "type": "bulletList", "content": [ { "type": "listItem", "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "Nested item" } ] } ] } ] } ]}Source
Section titled “Source”@domternal/core - ListItem.ts