noteloom

List item

One shared block type covers bulleted, numbered, to-do, and toggle lists — which flavor it is comes down to which props are set. Unlike paragraph/heading, a list item's own text lives in props.titleRunIds, not contentIdscontentIds is reserved for nested child blocks (indentation), which is why a list item is not a leaf block.

Variants

Bulleted / numbered

json
{ "id": "li1", "type": "listItem", "contentIds": [], "props": { "ordered": false, "titleRunIds": ["r1"] } }

ordered: true renders a numbered marker instead of a bullet. Neither checked nor collapsed is set.

To-do

json
{ "id": "li2", "type": "listItem", "contentIds": [], "props": { "ordered": false, "checked": false, "titleRunIds": ["r2"] } }

Setting checked (boolean) turns the marker into a checkbox.

Toggle

json
{ "id": "li3", "type": "listItem", "contentIds": ["p1"], "props": { "ordered": false, "collapsed": false, "titleRunIds": ["r3"] } }

Setting collapsed (boolean) turns the marker into a disclosure triangle. Nested content lives in contentIds and only renders while collapsed is false. A fresh toggle item is seeded with one empty paragraph child, since otherwise there would be no way to get content into it.

checked and collapsed are mutually exclusive — whichever is set decides which marker renders. Setting both is not a supported combination.

Nesting

Tab indents the current item under its previous sibling; Shift+Tab un-indents it — Notion-style. Enter on an empty item at the deepest level un-indents once before turning into a paragraph.

Slash commands

  • Bulleted list — keywords: list, bullet, ul
  • Numbered list — keywords: list, number, ordered, ol
  • To-do list — keywords: todo, checkbox, task, checklist
  • Toggle list — keywords: toggle, collapse, expand, dropdown, accordion

Markdown shortcuts also work: "- "/"* " for bulleted, "1. " for numbered, "[] " for to-do. Toggle lists are slash-command only — there's no markdown shortcut for them.

There's no shared role="list" ancestor wrapping sibling list items — each is an independent block, not grouped in the DOM. Adding role="listitem" without that ancestor would be worse than no role at all, so it's deliberately left out pending a bigger structural change.

Styling

.be-list-item on the item, .be-list-item-row for the marker+title row, and .be-list-item-children for the nested indent block.

Using it in your editor

useEditor() registers every built-in block by default, list item included. To register only the blocks you use instead:

jsx
import { useEditor, NoteloomEditor, registerBlocks, paragraphBlockType, listItemBlockType } from 'noteloom';

function Editor() {
  const editor = useEditor({
    registerBlocks: (registry) => registerBlocks(registry, { paragraph: paragraphBlockType, listItem: listItemBlockType }),
  });
  return <NoteloomEditor editor={editor} />;
}

See Picking only the blocks you want for combining this with other types.