insertOrderedList

How insertOrderedList inputType creates ordered lists and varies across browsers.

Overview

The insertOrderedList inputType is triggered when the user creates an ordered list (typically via toolbar or programmatically). The browser wraps selected paragraphs in an <ol> with <li> items.

Basic Behavior

Scenario: Multiple paragraphs selected

Before (Paragraphs selected)

HTML:
<p>Item 1</p>
<p>Item 2</p>
<p>Item 3</p>

After insertOrderedList

HTML:
<ol>
<li>Item 1</li>
<li>Item 2</li>
</ol>
<p>Item 3</p>
Selected paragraphs converted to list items

Browser-Specific Behavior

  • If selection is within an existing list, behavior varies: some browsers convert to ordered list, others merge items
  • Empty paragraphs may be converted to empty list items or ignored
  • Nested lists may be created if selection spans multiple levels

IME Composition + insertOrderedList

⚠️ Critical Issue

During IME composition, creating an ordered list may cancel the composition or commit it partially. The composition text may be lost or inserted incorrectly into list items.

Similar issues may occur with other block-level operations during composition.

Editor-Specific Handling

Different editor frameworks handle list creation differently. Here's how major editors implement insertOrderedList:

Slate.js

Ordered List Creation

Slate uses Transforms.wrapNodes() to wrap blocks in list containers:

    import { Editor, Transforms, Element } from 'slate';

element.addEventListener('beforeinput', (e) => {
  if (e.inputType === 'insertOrderedList') {
    e.preventDefault();
    
    // Check if already in a list
    const [match] = Editor.nodes(editor, {
      match: n => Element.isElement(n) && n.type === 'ordered-list',
    });
    
    if (match) {
      // Unwrap list
      Transforms.unwrapNodes(editor, {
        match: n => Element.isElement(n) && n.type === 'ordered-list',
      });
    } else {
      // Wrap in ordered list
      Transforms.wrapNodes(editor, {
        type: 'ordered-list',
        children: [],
      });
      
      // Convert blocks to list items
      Transforms.setNodes(editor, {
        type: 'list-item',
      });
    }
  }
});
  
  • Transforms.wrapNodes: Wraps selected blocks in a list container.
  • Block conversion: Converts paragraphs to list items using setNodes.
  • Toggle behavior: Can unwrap lists if already in a list.
ProseMirror

Ordered List Creation

ProseMirror uses wrapIn command to create lists:

    import { wrapIn } from 'prosemirror-commands';
import { schema } from './schema';

view.dom.addEventListener('beforeinput', (e) => {
  if (e.inputType === 'insertOrderedList') {
    e.preventDefault();
    const { state, dispatch } = view;
    
    // Check if already in ordered list
    const { $from } = state.selection;
    const listType = schema.nodes.ordered_list;
    const inList = $from.node(-1)?.type === listType;
    
    if (inList) {
      // Lift out of list
      const { lift } = require('prosemirror-transform');
      if (lift(state, dispatch)) {
        // Handled
      }
    } else {
      // Wrap in ordered list
      if (wrapIn(listType)(state, dispatch)) {
        // Handled
      }
    }
  }
});
  
  • wrapIn command: Wraps selection in a list node type.
  • Schema-based: Uses schema-defined list and list-item node types.
  • Lift command: Can lift content out of lists to toggle behavior.
Draft.js

Ordered List Creation

Draft.js uses RichUtils.toggleBlockType() for lists:

    import { EditorState, RichUtils } from 'draft-js';

function handleInsertOrderedList(editorState) {
  // Draft.js uses block-level styles for lists
  return RichUtils.toggleBlockType(editorState, 'ordered-list-item');
}

// In beforeinput handler
element.addEventListener('beforeinput', (e) => {
  if (e.inputType === 'insertOrderedList') {
    e.preventDefault();
    const newState = handleInsertOrderedList(editorState);
    setEditorState(newState);
  }
});
  
  • RichUtils.toggleBlockType: Toggles block type between paragraph and list-item.
  • Block types: Lists are represented as block types (e.g., 'ordered-list-item').
  • Serialization: Block types are converted to HTML list elements during rendering.

Related resources