From zbeyens. The source code is available on GitHub.

Plate
PlatePliteEditorsTemplates
GitHub16kGitHub
DiscordDiscord
    • Stream
    • Copilot
  • Discussion
    • Comments
    • Suggestion
    • Basic Blocks
      • Blockquote
      • Heading
      • Horizontal Rule
    • Callout
    • Code Block
    • Column
    • Date
    • Equation
    • Link
    • List Classic
    • Media
    • MentionElement
    • Table
    • Table of Contents
    • Footnote
    • Toggle
  • Marks
    • Bold
    • Italic
    • Underline
    • Code
    • Highlight
    • Keyboard Input
    • Strikethrough
    • Subscript
    • Superscript
      • Font
      • Line Height
      • Text Align
    • Indent
    • List
      • Exit Break
      • Single Block
      • Trailing Block
    • Autoformat
    • Block Menu
    • Block Placeholder
    • Combobox
      • Emoji
      • MentionElement
      • Slash Command
    • Cursor Overlay
    • Drag & Drop
    • Navigation Feedback
    • Tabbable
    • Toolbar
    • Yjs
    • Multi SelectEditor
    • CSV
    • DOCX
    • HTML
    • Markdown

Slash Command

PreviousNext

Slash command menu for quick insertion of various content types.

PlusComboboxSlash Nodes
Loading…
EmojiCursor Overlay

On This Page

FeaturesKit UsageInstallationAdd KitManual UsageInstallationAdd PluginsConfigure PluginsUsagePlate PlusPluginsSlashPluginSlashInputPlugin
Build your editor
Production-ready AI template and reusable components.
Get all-access

Features

  • Quick access to various editor commands
  • Triggered by / character
  • Keyboard navigation and filtering
  • Customizable command groups and options
Report an issue

Kit Usage

Installation

The fastest way to add slash command functionality is with the SlashKit, which includes pre-configured SlashPlugin and SlashInputPlugin along with their Plate UI components.

'use client';
 
import { AIChatPlugin } from '@platejs/ai/react';
import { SlashInputPlugin, SlashPlugin } from '@platejs/slash-command/react';
import {
  CalendarIcon,
  ChevronRightIcon,
  Code2,
  Columns3Icon,
  Heading1Icon,
  Heading2Icon,
  Heading3Icon,
  LightbulbIcon,
  ListIcon,
  ListOrdered,
  PenToolIcon,
  PilcrowIcon,
  Quote,
  RadicalIcon,
  SparklesIcon,
  Square,
  SuperscriptIcon,
  Table,
  TableOfContentsIcon,
} from 'lucide-react';
import { PLUGINS } from 'platejs';
import {
  type PlateEditor,
  type PlateElementProps,
  PlateElement,
} from 'platejs/react';
import * as React from 'react';
 
import {
  insertBlock,
  insertInlineElement,
} from '@/components/editor/transforms';
 
import {
  InlineCombobox,
  InlineComboboxContent,
  InlineComboboxEmpty,
  InlineComboboxGroup,
  InlineComboboxGroupLabel,
  InlineComboboxInput,
  InlineComboboxItem,
} from './inline-combobox';
 
type Group = {
  group: string;
  items: Array<{
    icon: React.ReactNode;
    value: string;
    onSelect: (editor: PlateEditor, value: string) => void;
    className?: string;
    focusEditor?: boolean;
    keywords?: string[];
    label?: string;
  }>;
};
 
const groups: Group[] = [
  {
    group: 'AI',
    items: [
      {
        focusEditor: false,
        icon: <SparklesIcon />,
        value: 'AI',
        onSelect: (editor) => {
          editor.plugin(AIChatPlugin).api.show();
        },
      },
    ],
  },
  {
    group: 'Basic blocks',
    items: [
      {
        icon: <PilcrowIcon />,
        keywords: ['paragraph'],
        label: 'Text',
        value: PLUGINS.paragraph,
      },
      {
        icon: <Heading1Icon />,
        keywords: ['title', 'h1'],
        label: 'Heading 1',
        value: 'heading-1',
      },
      {
        icon: <Heading2Icon />,
        keywords: ['subtitle', 'h2'],
        label: 'Heading 2',
        value: 'heading-2',
      },
      {
        icon: <Heading3Icon />,
        keywords: ['subtitle', 'h3'],
        label: 'Heading 3',
        value: 'heading-3',
      },
      {
        icon: <ListIcon />,
        keywords: ['unordered', 'ul', '-'],
        label: 'Bulleted list',
        value: 'disc',
      },
      {
        icon: <ListOrdered />,
        keywords: ['ordered', 'ol', '1'],
        label: 'Numbered list',
        value: 'decimal',
      },
      {
        icon: <Square />,
        keywords: ['checklist', 'task', 'checkbox', '[]'],
        label: 'To-do list',
        value: 'todo',
      },
      {
        icon: <ChevronRightIcon />,
        keywords: ['collapsible', 'expandable'],
        label: 'Toggle',
        value: PLUGINS.toggle,
      },
      {
        icon: <Code2 />,
        keywords: ['```'],
        label: 'Code Block',
        value: PLUGINS.codeBlock,
      },
      {
        icon: <Table />,
        label: 'Table',
        value: PLUGINS.table,
      },
      {
        icon: <Quote />,
        keywords: ['citation', 'blockquote', 'quote', '>'],
        label: 'Blockquote',
        value: PLUGINS.blockquote,
      },
      {
        description: 'Insert a highlighted block.',
        icon: <LightbulbIcon />,
        keywords: ['note'],
        label: 'Callout',
        value: PLUGINS.callout,
      },
    ].map((item) => ({
      ...item,
      onSelect: (editor, value) => {
        insertBlock(editor, value, { upsert: true });
      },
    })),
  },
  {
    group: 'Advanced blocks',
    items: [
      {
        icon: <TableOfContentsIcon />,
        keywords: ['toc'],
        label: 'Table of contents',
        value: PLUGINS.toc,
      },
      {
        icon: <Columns3Icon />,
        label: '3 columns',
        value: 'action_three_columns',
      },
      {
        focusEditor: false,
        icon: <RadicalIcon />,
        label: 'Equation',
        value: PLUGINS.equation,
      },
      {
        icon: <PenToolIcon />,
        keywords: ['excalidraw'],
        label: 'Excalidraw',
        value: PLUGINS.excalidraw,
      },
      {
        icon: <Code2 />,
        keywords: [
          'code-drawing',
          'diagram',
          'plantuml',
          'graphviz',
          'flowchart',
          'mermaid',
        ],
        label: 'Code Drawing',
        value: PLUGINS.codeDrawing,
      },
    ].map((item) => ({
      ...item,
      onSelect: (editor, value) => {
        insertBlock(editor, value, { upsert: true });
      },
    })),
  },
  {
    group: 'Inline',
    items: [
      {
        focusEditor: true,
        icon: <CalendarIcon />,
        keywords: ['time'],
        label: 'Date',
        value: PLUGINS.date,
      },
      {
        focusEditor: true,
        icon: <SuperscriptIcon />,
        keywords: ['citation', 'fn', 'footnote', '[^]'],
        label: 'Footnote',
        value: 'action_footnote',
      },
      {
        focusEditor: false,
        icon: <RadicalIcon />,
        label: 'Inline Equation',
        value: PLUGINS.inlineEquation,
      },
    ].map((item) => ({
      ...item,
      onSelect: (editor, value) => {
        insertInlineElement(editor, value);
      },
    })),
  },
];
 
export function SlashInputElement(
  props: PlateElementProps<typeof SlashInputPlugin>
) {
  const { editor, element } = props;
 
  return (
    <PlateElement {...props} as="span">
      <InlineCombobox element={element} trigger="/">
        <InlineComboboxInput />
 
        <InlineComboboxContent>
          <InlineComboboxEmpty>No results</InlineComboboxEmpty>
 
          {groups.map(({ group, items }) => (
            <InlineComboboxGroup key={group}>
              <InlineComboboxGroupLabel>{group}</InlineComboboxGroupLabel>
 
              {items.map(
                ({ focusEditor, icon, keywords, label, value, onSelect }) => (
                  <InlineComboboxItem
                    key={value}
                    value={value}
                    onClick={() => {
                      onSelect(editor, value);
                    }}
                    label={label}
                    focusEditor={focusEditor}
                    group={group}
                    keywords={keywords}
                  >
                    <div className="mr-2 text-muted-foreground">{icon}</div>
                    {label ?? value}
                  </InlineComboboxItem>
                )
              )}
            </InlineComboboxGroup>
          ))}
        </InlineComboboxContent>
      </InlineCombobox>
 
      {props.children}
    </PlateElement>
  );
}
 
export const SlashKit = [
  SlashPlugin.configure({
    initialState: {
      triggerQuery: (editor) => {
        const codeBlock = editor.plugin(PLUGINS.codeBlock);
 
        return !editor.read.nodes.some({
          type: codeBlock.schema.type,
        });
      },
    },
  }),
  SlashInputPlugin.configure({ component: SlashInputElement }),
];
'use client';
 
import { AIChatPlugin } from '@platejs/ai/react';
import { SlashInputPlugin, SlashPlugin } from '@platejs/slash-command/react';
import {
  CalendarIcon,
  ChevronRightIcon,
  Code2,
  Columns3Icon,
  Heading1Icon,
  Heading2Icon,
  Heading3Icon,
  LightbulbIcon,
  ListIcon,
  ListOrdered,
  PenToolIcon,
  PilcrowIcon,
  Quote,
  RadicalIcon,
  SparklesIcon,
  Square,
  SuperscriptIcon,
  Table,
  TableOfContentsIcon,
} from 'lucide-react';
import { PLUGINS } from











































































































































































































































































  • SlashInputElement: Renders the slash command combobox with predefined options

Add Kit

import { createPlateEditor } from 'platejs/react';
import { SlashKit } from '@/components/editor/slash';
 
const editor = createPlateEditor({
  plugins: [
    // ...otherPlugins,
    ...SlashKit,
  ],
});
import { createPlateEditor } from 'platejs/react';
import { SlashKit } from '@/components/editor/slash';
 
const editor = createPlateEditor({




Manual Usage

Installation

pnpm add @platejs/slash-command
pnpm add @platejs/slash-command

Add Plugins

SlashPlugin installs SlashInputPlugin as a required dependency.

import { SlashPlugin } from '@platejs/slash-command/react';
import { createPlateEditor } from 'platejs/react';
 
const editor = createPlateEditor({
  plugins: [
    // ...otherPlugins,
    SlashPlugin,
  ],
});
import { SlashPlugin } from '@platejs/slash-command/react';
import { createPlateEditor } from 'platejs/react';
 
const editor = createPlateEditor({




Configure Plugins

Add a complete SlashInputPlugin descriptor beside the owner when you need to replace the dependency's component or configuration.

import {
  SlashInputPlugin,
  SlashPlugin,
} from '@platejs/slash-command/react';
import { PLUGINS } from 'platejs';
import { createPlateEditor } from 'platejs/react';
import { SlashInputElement } from '@/components/editor/slash';
 
const editor = createPlateEditor({
  plugins: [
    // ...otherPlugins,
    SlashPlugin.configure({
      initialState: {
        trigger: '/',
        triggerPreviousCharPattern: /^\s?$/,
        triggerQuery: (editor) => {











  • initialState.trigger: Character that triggers the slash command combobox (default: /)
  • initialState.triggerPreviousCharPattern: RegExp pattern for character before trigger
  • initialState.triggerQuery: Function to determine when slash commands should be enabled
  • component: Assigns the UI component for the slash command interface

Usage

How to use slash commands:

  1. Type / anywhere in your document to open the slash menu
  2. Start typing to filter options or use arrow keys to navigate
  3. Press Enter or click to select an option
  4. Press Escape to close the menu without selecting

Available options include:

  • Text blocks (paragraphs, headings)
  • Lists (bulleted, numbered, to-do)
  • Advanced blocks (tables, code blocks, callouts)
  • Inline elements (dates, equations)

Use keywords to quickly find options. For example, type '/ul' for Bulleted List or '/h1' for Heading 1.

Plate Plus

  • Extended set of slash menu options like "Ask AI"
  • Trigger slash menu by click the + button on the left gutter
  • Item groups
  • Beautifully crafted UI
Get the code

Plugins

SlashPlugin

Plugin for slash command functionality. Extends TriggerComboboxPluginState and requires SlashInputPlugin.

Options

    Character that triggers slash command combobox.

    • Default: '/'

    RegExp to match character before trigger.

    • Default: /^\s?$/

    Function to create combobox input element.

    • Default:
    () => ({
      children: [{ text: '' }],
      type: 'slashInput',
    });
    () => ({
      children: [{ text: '' }],
      type: 'slashInput',
    });

    Function to determine when slash commands should be enabled. Useful for disabling in certain contexts like code blocks.

SlashInputPlugin

Required input dependency for slash command insertion. Add it directly only to replace its component or configuration.

'platejs'
;
import {
type PlateEditor,
type PlateElementProps,
PlateElement,
} from 'platejs/react';
import * as React from 'react';
import {
insertBlock,
insertInlineElement,
} from '@/components/editor/transforms';
import {
InlineCombobox,
InlineComboboxContent,
InlineComboboxEmpty,
InlineComboboxGroup,
InlineComboboxGroupLabel,
InlineComboboxInput,
InlineComboboxItem,
} from './inline-combobox';
type Group = {
group: string;
items: Array<{
icon: React.ReactNode;
value: string;
onSelect: (editor: PlateEditor, value: string) => void;
className?: string;
focusEditor?: boolean;
keywords?: string[];
label?: string;
}>;
};
const groups: Group[] = [
{
group: 'AI',
items: [
{
focusEditor: false,
icon: <SparklesIcon />,
value: 'AI',
onSelect: (editor) => {
editor.plugin(AIChatPlugin).api.show();
},
},
],
},
{
group: 'Basic blocks',
items: [
{
icon: <PilcrowIcon />,
keywords: ['paragraph'],
label: 'Text',
value: PLUGINS.paragraph,
},
{
icon: <Heading1Icon />,
keywords: ['title', 'h1'],
label: 'Heading 1',
value: 'heading-1',
},
{
icon: <Heading2Icon />,
keywords: ['subtitle', 'h2'],
label: 'Heading 2',
value: 'heading-2',
},
{
icon: <Heading3Icon />,
keywords: ['subtitle', 'h3'],
label: 'Heading 3',
value: 'heading-3',
},
{
icon: <ListIcon />,
keywords: ['unordered', 'ul', '-'],
label: 'Bulleted list',
value: 'disc',
},
{
icon: <ListOrdered />,
keywords: ['ordered', 'ol', '1'],
label: 'Numbered list',
value: 'decimal',
},
{
icon: <Square />,
keywords: ['checklist', 'task', 'checkbox', '[]'],
label: 'To-do list',
value: 'todo',
},
{
icon: <ChevronRightIcon />,
keywords: ['collapsible', 'expandable'],
label: 'Toggle',
value: PLUGINS.toggle,
},
{
icon: <Code2 />,
keywords: ['```'],
label: 'Code Block',
value: PLUGINS.codeBlock,
},
{
icon: <Table />,
label: 'Table',
value: PLUGINS.table,
},
{
icon: <Quote />,
keywords: ['citation', 'blockquote', 'quote', '>'],
label: 'Blockquote',
value: PLUGINS.blockquote,
},
{
description: 'Insert a highlighted block.',
icon: <LightbulbIcon />,
keywords: ['note'],
label: 'Callout',
value: PLUGINS.callout,
},
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertBlock(editor, value, { upsert: true });
},
})),
},
{
group: 'Advanced blocks',
items: [
{
icon: <TableOfContentsIcon />,
keywords: ['toc'],
label: 'Table of contents',
value: PLUGINS.toc,
},
{
icon: <Columns3Icon />,
label: '3 columns',
value: 'action_three_columns',
},
{
focusEditor: false,
icon: <RadicalIcon />,
label: 'Equation',
value: PLUGINS.equation,
},
{
icon: <PenToolIcon />,
keywords: ['excalidraw'],
label: 'Excalidraw',
value: PLUGINS.excalidraw,
},
{
icon: <Code2 />,
keywords: [
'code-drawing',
'diagram',
'plantuml',
'graphviz',
'flowchart',
'mermaid',
],
label: 'Code Drawing',
value: PLUGINS.codeDrawing,
},
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertBlock(editor, value, { upsert: true });
},
})),
},
{
group: 'Inline',
items: [
{
focusEditor: true,
icon: <CalendarIcon />,
keywords: ['time'],
label: 'Date',
value: PLUGINS.date,
},
{
focusEditor: true,
icon: <SuperscriptIcon />,
keywords: ['citation', 'fn', 'footnote', '[^]'],
label: 'Footnote',
value: 'action_footnote',
},
{
focusEditor: false,
icon: <RadicalIcon />,
label: 'Inline Equation',
value: PLUGINS.inlineEquation,
},
].map((item) => ({
...item,
onSelect: (editor, value) => {
insertInlineElement(editor, value);
},
})),
},
];
export function SlashInputElement(
props: PlateElementProps<typeof SlashInputPlugin>
) {
const { editor, element } = props;
return (
<PlateElement {...props} as="span">
<InlineCombobox element={element} trigger="/">
<InlineComboboxInput />
<InlineComboboxContent>
<InlineComboboxEmpty>No results</InlineComboboxEmpty>
{groups.map(({ group, items }) => (
<InlineComboboxGroup key={group}>
<InlineComboboxGroupLabel>{group}</InlineComboboxGroupLabel>
{items.map(
({ focusEditor, icon, keywords, label, value, onSelect }) => (
<InlineComboboxItem
key={value}
value={value}
onClick={() => {
onSelect(editor, value);
}}
label={label}
focusEditor={focusEditor}
group={group}
keywords={keywords}
>
<div className="mr-2 text-muted-foreground">{icon}</div>
{label ?? value}
</InlineComboboxItem>
)
)}
</InlineComboboxGroup>
))}
</InlineComboboxContent>
</InlineCombobox>
{props.children}
</PlateElement>
);
}
export const SlashKit = [
SlashPlugin.configure({
initialState: {
triggerQuery: (editor) => {
const codeBlock = editor.plugin(PLUGINS.codeBlock);
return !editor.read.nodes.some({
type: codeBlock.schema.type,
});
},
},
}),
SlashInputPlugin.configure({ component: SlashInputElement }),
];
plugins: [
// ...otherPlugins,
...SlashKit,
],
});
plugins: [
// ...otherPlugins,
SlashPlugin,
],
});
const
codeBlock
=
editor.
plugin
(
PLUGINS
.codeBlock);
return (
!codeBlock.installed ||
!editor.read.nodes.some({ type: codeBlock.schema.type })
);
},
},
}),
SlashInputPlugin.configure({ component: SlashInputElement }),
],
});
import {
  SlashInputPlugin,
  SlashPlugin,
} from '@platejs/slash-command/react';
import { PLUGINS } from 'platejs';
import { createPlateEditor } from 'platejs/react';
import { SlashInputElement } from '@/components/editor/slash';
 
const editor = createPlateEditor({
  plugins: [
    // ...otherPlugins,
    SlashPlugin.configure({
      initialState: {
        trigger: '/',
        triggerPreviousCharPattern: /^\s?$/,
        triggerQuery: (editor) => {
          const codeBlock = editor.plugin(PLUGINS.codeBlock);
 
          return (
            !codeBlock.installed ||
            !editor.read.nodes.some({ type: codeBlock.schema.type })
          );
        },
      },
    }),
    SlashInputPlugin.configure({ component: SlashInputElement }),
  ],
});