Bullet List
The BulletList node provides a block-level unordered list container (<ul>). It includes markdown-style input rules (-, *, or + followed by space), a keyboard shortcut (Mod-Shift-8), and automatic inclusion of the ListItem node and ListKeymap extension for Tab/Shift-Tab indentation.
Live Playground
Section titled “Live Playground”Type -, *, or + followed by space at the start of a line to create a bullet list. Use Tab to indent and Shift-Tab to outdent.
Vanilla JS preview - Angular components produce the same output
Vanilla JS preview - React components produce the same output
The button above the editor is a custom HTML button wired to toggleBulletList(). Active state is tracked with editor.isActive('bulletList').
BulletList is included in StarterKit. If you are building a custom setup without StarterKit, add it manually:
import { Editor, Document, Text, Paragraph, BulletList } from '@domternal/core';
const editor = new Editor({ element: document.getElementById('editor')!, extensions: [Document, Text, Paragraph, BulletList], 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 } 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]; 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 } from '@domternal/core';
export default function Editor() { return ( <Domternal extensions={[Document, Text, Paragraph, BulletList]} content="<ul><li><p>First item</p></li><li><p>Second item</p></li></ul>" > <Domternal.Content /> </Domternal> );}Schema
Section titled “Schema”| Property | Value |
|---|---|
| ProseMirror name | bulletList |
| Type | Node |
| Group | block list |
| Content | listItem+ (one or more list items) |
| HTML tag | <ul> |
The list group allows ProseMirror to identify this node as a list container, which is used by list-related commands like toggleList.
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
HTMLAttributes | Record<string, unknown> | {} | HTML attributes added to the <ul> element |
itemTypeName | string | 'listItem' | Name of the list item node type used by toggleList |
Custom HTML attributes
Section titled “Custom HTML attributes”import { BulletList } from '@domternal/core';
const CustomBulletList = BulletList.configure({ HTMLAttributes: { class: 'my-list' },});Commands
Section titled “Commands”| Command | Description |
|---|---|
toggleBulletList() | Toggle the current selection between bullet list and paragraph |
// Toggle bullet list on/offeditor.commands.toggleBulletList();
// With chainingeditor.chain().focus().toggleBulletList().run();toggleBulletList wraps the selected blocks in a <ul> with <li> items. If the selection is already inside a bullet list, it unwraps it back to paragraphs. If the selection is inside a different list type (ordered list, task list), it converts it to a bullet list.
Keyboard shortcuts
Section titled “Keyboard shortcuts”| Shortcut | Command |
|---|---|
Mod-Shift-8 | toggleBulletList() |
Enter | Split list item at cursor, or lift out of list if empty |
Tab | Indent list item (sink) |
Shift-Tab | Outdent list item (lift) |
Backspace | Lift 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 BulletList.
Input rules
Section titled “Input rules”| Input | Result |
|---|---|
- + space | Bullet list item |
* + space | Bullet list item |
+ + space | Bullet list item |
Type one of these characters at the start of a new line, then press space. The line wraps in a bullet list. These input rules only fire outside of existing lists - typing - + space inside a list item inserts the characters as plain text. To nest lists, use Tab to indent a list item.
Toolbar items
Section titled “Toolbar items”BulletList registers a button in the toolbar with the name bulletList in group lists at priority 200.
| Item | Command | Icon | Shortcut |
|---|---|---|---|
| Bullet List | toggleBulletList | listBullets | Mod-Shift-8 |
Included extensions
Section titled “Included extensions”BulletList automatically includes these extensions via addExtensions():
| Extension | Description |
|---|---|
| ListItem | The <li> node used inside the list |
| ListKeymap | Tab/Shift-Tab indentation and Backspace handling (included by ListItem) |
This means adding BulletList to your extensions array is sufficient. You don’t need to add ListItem or ListKeymap separately.
JSON representation
Section titled “JSON representation”{ "type": "bulletList", "content": [ { "type": "listItem", "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "First item" } ] } ] }, { "type": "listItem", "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "Second item" } ] } ] } ]}A nested bullet list:
{ "type": "bulletList", "content": [ { "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 - BulletList.ts