npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tiptap-extension-flat-list

v0.1.1

Published

Tiptap extension that adds "flat" list items

Readme

tiptap-extension-flat-list

A set of Tiptap extensions that implement lists (ordered, unordered, and task) using a "flat" data model, where each list item is a top-level block with inline content. You can use these to implement a Notion-style editor where the document is a list of blocks with inline content, instead of a general tree.

Unlike HTML or Tiptap's list extensions, list items are not wrapped in list blocks (OL/UL). Also, nested lists are represented purely by indent levels: the "children" of a list item are actually siblings in the ProseMirror tree, just with an indent attribute that affects their rendering. These indents are constrained to look like an actual nested list (indent <= previous indent + 1).

The library is compatible with normal HTML lists---both when parsing/serializing state and when interacting with the clipboard---if you use our Helper Functions. In the editor itself, each flat list item is rendered as a list (OL/UL) containing a single LI, with some rendering tricks to make these look like normal joined and nested lists.

Why flat lists?

Our flat list data model is inspired by the Quill rich-text editor. Quill models text as a plain text string plus inline formatting; blocks are represented by newline characters, with each block's type given by formatting on the newline. While Quill is less powerful than ProseMirror, its simple data model is easy to use compared to ProseMirror's tree of nodes.

Benefits of flat list items:

  • Reason about list items like any other top-level block (paragraphs, headings, etc.).
  • Simpler commands---no need to lift/sink blocks or check for wrapper OL/UL blocks.
  • Easier to make sense of changes in a collaborative setting.
    • In particular, it's straightforward to model a flat sequence of blocks (with inline content) as a CRDT: take a CRDT for non-block text (e.g. Peritext) and add special "new block" characters that indicate where the next block starts and its type. This CRDT automatically handles block splitting and merging in the obvious way.

The library code is based on prosemirror-flat-list. Our main difference is that list items have inline content only. In particular, nested lists use indented siblings instead of list blocks nested inside list items. Also, we provide Tiptap extensions instead of ProseMirror utilities.

Docs

Install

npm i tiptap-extension-flat-list

Tiptap Extensions

  • FlatListCore (required): Core functionality required by the other extensions.
  • FlatListOrdered: Adds support for ordered flat list items (<ol><li> ... </li></ol>).
  • FlatListUnordered: Adds support for unordered flat list items (<ul><li> ... </li></ul>).
  • FlatListTask: Adds support for task flat list items, i.e., to-do lists. These are rendered and serialized using HTML checkbox inputs; in the clipboard, they are converted to plain unordered list items (with data attributes to remember them when pasting into Tiptap itself).

Helper Functions

When serializing HTML for external consumption, it is good practice to convert flat list items to normal HTML lists. Our extensions don't do so by default, but you can easily enable that functionality:

  • Call JoinListDOMSerializer.setClipboardSerializer(editor) when setting up your editor to patch copying to the clipboard.
  • Call JoinListDOMSerializer.getHTML(editor) in place of editor.getHTML().

These functions join neighboring flat list items into a single <ul> and <ol> element, convert indented list items to nested HTML lists, and clean up the HTML a bit (especially when copying).

Parsing normal HTML lists should work out-of-the-box. In particular, saving html = JoinListDOMSerializer.getHTML(editor) and later loading it with editor.setContent(html) yields the same editor state. Of course, there are always edge cases when parsing HTML generated by external programs.

Example Setup

See demo/.

import {
  FlatListCore,
  FlatListOrdered,
  FlatListTask,
  FlatListUnordered,
  JoinListDOMSerializer,
} from "tiptap-extension-flat-list";
// ...

const editor = new Editor({
  element: document.querySelector(".element"),
  extensions: [
    Document,
    Paragraph,
    Text,
    FlatListCore,
    FlatListOrdered,
    FlatListUnordered,
    FlatListTask,
    // Other extensions...
  ],
  content: "<p>Hello World!</p>",
});

JoinListDOMSerializer.setClipboardSerializer(editor);

// To export HTML that uses normal HTML lists, instead of editor.getHTML(), call:
console.log(JoinListDOMSerializer.getHTML(editor));

Commands

Note type ListType = "ordered" | "unordered" | "task".

setFlatListItem

Sets a flat list item node.

If attributes.indent is not provided and any selected nodes are already flat list nodes (possibly a different ListType), their indent is preserved.

editor.commands.setFlatListItem(
  listType: ListType,
  attributes?: { indent?: number; checked?: boolean }
)

toggleFlatListItem

Toggles a flat list item node.

When toggling on, if attributes.indent is not provided and any selected nodes are already flat list nodes (possibly a different ListType), their indent is preserved.

editor.commands.toggleFlatListItem(
  listType: ListType,
  attributes?: { indent?: number; checked?: boolean }
)

indentFlatListItem

Dedents (un-indent) the flat list item(s) overlapping the current selection. If an affected item's indent is 0 and canConvert is true, the item is converted to a paragraph.

This will also dedent all "descendants" of the last affected item (subsequent list items with greater indent).

editor.commands.indentFlatListItem();

dedentFlatListItem

Dedents (un-indents) the flat list item(s) overlapping the current selection. If an affected item's indent is 0 and canConvert is true, the item is converted to a paragraph.

This will also dedent all "descendants" of the last affected item (subsequent list items with greater indent).

editor.commands.dedentFlatListItem(canConvert?: boolean)

Developing

  • Install dependencies with npm install.
  • Run the demo (in demo/) with npm start.
  • Build with npm run build, or build in watch mode with npm run watch.
  • Lint and check format with npm run test.
  • Preview typedoc with npm run docs. (Open docs/index.html in a browser.)