'use client';
import * as React from 'react';
import { Plate, usePlateEditor } from 'platejs/react';
import { EditorKit } from '@/components/editor/editor-kit';
import { AutoformatKit } from '@/components/editor/plugins/autoformat-classic-kit';
import { FixedToolbarKit } from '@/components/editor/plugins/fixed-toolbar-classic-kit';
import { ListKit } from '@/components/editor/plugins/list-classic-kit';
import { listValue } from '@/registry/examples/values/list-classic-value';
import { Editor, EditorContainer } from '@/components/ui/editor';
export default function ListClassicDemo() {
const editor = usePlateEditor({
// Disable EditorKit's indent and list plugins
override: {
enabled: {
indent: false,
list: false,
},
},
plugins: [...EditorKit, ...ListKit, ...FixedToolbarKit, ...AutoformatKit],
value: listValue,
});
return (
<Plate editor={editor}>
<EditorContainer variant="demo">
<Editor />
</EditorContainer>
</Plate>
);
}
Choose Your List Plugin
Plate offers two approaches for implementing lists:
-
This List Classic plugin - Traditional HTML-spec lists with strict nesting rules:
- Follows standard HTML list structure (
ul
/ol
>li
) - Maintains consistent list hierarchy
- Best for content that may be exported to HTML/markdown
- Highest complexity
- Follows standard HTML list structure (
-
The List plugin - Flexible indentation-based lists:
- More like Word/Google Docs behavior
- Any block can be indented to create list-like structures
- Used in the AI editor
- Supports nested todo lists
- Better for free-form content organization
Choose based on your needs:
- Use the List Classic plugin when you need standard HTML list compatibility
- Use the List plugin when you want more flexible indentation behavior
Features
-
HTML-compliant lists:
- Standard
ul
/ol
>li
structure - Proper nesting and hierarchy
- SEO-friendly markup
- Clean HTML/markdown export
- Standard
-
List types:
- Unordered (bulleted) lists
- Ordered (numbered) lists
- Nested sublists
-
Drag & drop:
- Currently supports root-level list items only
- Sibling and nested items drag & drop not yet supported
-
Shortcuts:
- Combined with the autoformat plugin, use markdown shortcuts (
-
,*
,1.
) to create lists - Tab/Shift+Tab for indentation control
- Combined with the autoformat plugin, use markdown shortcuts (
-
Limitations (use the List plugin for these features):
- Drag & drop only supports root-level lists
- List items cannot be aligned
For a more flexible, Word-like approach, see the List plugin.
Kit Usage
Installation
The fastest way to add list functionality is with the ListKit
, which includes pre-configured list plugins with Plate UI components and keyboard shortcuts.
'use client';
import {
BulletedListPlugin,
ListItemPlugin,
ListPlugin,
NumberedListPlugin,
} from '@platejs/list-classic/react';
import {
BulletedListElement,
NumberedListElement,
} from '@/components/ui/list-classic-node';
export const ListKit = [
ListPlugin,
BulletedListPlugin.configure({
node: { component: BulletedListElement },
shortcuts: { toggle: { keys: 'mod+alt+5' } },
}),
NumberedListPlugin.configure({
node: { component: NumberedListElement },
shortcuts: { toggle: { keys: 'mod+alt+6' } },
}),
ListItemPlugin,
];
BulletedListElement
: Renders unordered list elements.NumberedListElement
: Renders ordered list elements.
Add Kit
Add the kit to your plugins:
import { createPlateEditor } from 'platejs/react';
import { ListKit } from '@/components/editor/plugins/list-classic-kit';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
...ListKit,
],
});
Manual Usage
Installation
pnpm add @platejs/list-classic
Add Plugins
Include the list plugins in your Plate plugins array when creating the editor.
import { ListPlugin, BulletedListPlugin, NumberedListPlugin, ListItemPlugin } from '@platejs/list-classic/react';
import { createPlateEditor } from 'platejs/react';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
ListPlugin,
BulletedListPlugin,
NumberedListPlugin,
ListItemPlugin,
],
});
Configure Plugins
Configure the plugins with custom components and keyboard shortcuts.
import { ListPlugin, BulletedListPlugin, NumberedListPlugin, ListItemPlugin } from '@platejs/list-classic/react';
import { createPlateEditor } from 'platejs/react';
import { BulletedListElement, NumberedListElement } from '@/components/ui/list-classic-node';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
ListPlugin,
BulletedListPlugin.configure({
node: { component: BulletedListElement },
shortcuts: { toggle: { keys: 'mod+alt+5' } },
}),
NumberedListPlugin.configure({
node: { component: NumberedListElement },
shortcuts: { toggle: { keys: 'mod+alt+6' } },
}),
ListItemPlugin,
],
});
node.component
: AssignsBulletedListElement
andNumberedListElement
to render list elements.shortcuts.toggle
: Defines keyboard shortcuts to toggle list types (mod+alt+5
for bulleted,mod+alt+6
for numbered).
Add Toolbar Button
You can add ListToolbarButton
to your Toolbar to create and manage lists.
Turn Into Toolbar Button
You can add these items to the Turn Into Toolbar Button to convert blocks into lists:
{
icon: <ListIcon />,
label: 'Bulleted list',
value: KEYS.ul,
}
{
icon: <ListOrderedIcon />,
label: 'Numbered list',
value: KEYS.ol,
}
Insert Toolbar Button
You can add these items to the Insert Toolbar Button to insert list elements:
{
icon: <ListIcon />,
label: 'Bulleted list',
value: KEYS.ul,
}
{
icon: <ListOrderedIcon />,
label: 'Numbered list',
value: KEYS.ol,
}
Plugins
ListPlugin
BulletedListPlugin
Plugin for unordered (bulleted) lists.
NumberedListPlugin
Plugin for ordered (numbered) lists.
ListItemPlugin
Plugin for list items.
ListItemContentPlugin
Plugin for list item content.
Transforms
tf.ul.toggle()
Toggles a bulleted list (ul).
Example Shortcut: Mod+Alt+5
tf.ol.toggle()
Toggles an ordered list (ol).
Example Shortcut: Mod+Alt+6
API
getHighestEmptyList
Finds the highest end list that can be deleted. The path of the list should be different from diffListPath
. If the highest end list has 2 or more items, returns liPath
. It traverses up the parent lists until:
- The list has less than 2 items
- Its path is not equal to
diffListPath
getListItemEntry
Returns the nearest li
and ul
/ol
wrapping node entries for a given path (default = selection
).
getListRoot
Searches upward for root list element.
getListTypes
Gets array of supported list types.
moveListSiblingsAfterCursor
Moves list siblings after cursor to specified path.
removeFirstListItem
Removes first list item if not nested and not first child.
removeListItem
Removes list item and moves sublist to parent if any.
someList
Checks if selection is inside list of specific type.
unindentListItems
Decreases indentation level of list items.
unwrapList
Removes list formatting from selected items.
Hooks
useListToolbarButton
A behavior hook for a list toolbar button.
On This Page
FeaturesKit UsageInstallationAdd KitManual UsageInstallationAdd PluginsConfigure PluginsAdd Toolbar ButtonTurn Into Toolbar ButtonInsert Toolbar ButtonPluginsListPluginBulletedListPluginNumberedListPluginListItemPluginListItemContentPluginTransformstf.ul.toggle()tf.ol.toggle()APIgetHighestEmptyListgetListItemEntrygetListRootgetListTypesmoveListSiblingsAfterCursorremoveFirstListItemremoveListItemsomeListunindentListItemsunwrapListHooksuseListToolbarButton