Skip to main content

Quick start

Add SlashCommand.Root with the default command set:
import { StarterKit } from '@react-email/editor/extensions';
import { defaultSlashCommands, SlashCommand } from '@react-email/editor/ui';
import { EditorProvider } from '@tiptap/react';
import '@react-email/editor/themes/default.css';

const extensions = [StarterKit];

export function MyEditor() {
  return (
    <EditorProvider extensions={extensions} content={content}>
      <SlashCommand.Root items={defaultSlashCommands} />
    </EditorProvider>
  );
}
Type / in the editor to open the command menu. Use arrow keys to navigate and Enter to select.

Default commands

The defaultSlashCommands array includes these built-in commands:
CommandCategoryDescription
TEXTTextPlain text block
H1TextLarge heading
H2TextMedium heading
H3TextSmall heading
BULLET_LISTTextUnordered list
NUMBERED_LISTTextOrdered list
QUOTETextBlock quote
CODETextCode snippet
BUTTONLayoutClickable button
DIVIDERLayoutHorizontal separator
SECTIONLayoutContent section
TWO_COLUMNSLayoutTwo column layout
THREE_COLUMNSLayoutThree column layout
FOUR_COLUMNSLayoutFour column layout
Each command is also exported individually, so you can cherry-pick:
import { BUTTON, H1, H2, TEXT } from '@react-email/editor/ui';

<SlashCommand.Root items={[TEXT, H1, H2, BUTTON]} />

Adding custom commands

Create a SlashCommandItem and include it in the items array:
import {
  defaultSlashCommands,
  SlashCommand,
  type SlashCommandItem,
} from '@react-email/editor/ui';
import { Star } from 'lucide-react';

const GREETING: SlashCommandItem = {
  title: 'Greeting',
  description: 'Insert a greeting block',
  icon: <Star size={20} />,
  category: 'Custom',
  searchTerms: ['hello', 'greeting', 'welcome'],
  command: ({ editor, range }) => {
    editor
      .chain()
      .focus()
      .deleteRange(range)
      .insertContent({
        type: 'paragraph',
        content: [{ type: 'text', text: 'Hello! Welcome to our newsletter.' }],
      })
      .run();
  },
};

export function MyEditor() {
  return (
    <EditorProvider extensions={extensions} content={content}>
      <SlashCommand.Root
        items={[...defaultSlashCommands, GREETING]}
      />
    </EditorProvider>
  );
}
The SlashCommandItem interface:
title
string
required
Display name shown in the command list.
description
string
required
Help text shown below the title.
icon
ReactNode
required
Icon displayed next to the command.
category
string
required
Category for grouping commands in the list.
searchTerms
string[]
Additional terms for fuzzy search matching.
command
(props: { editor, range }) => void
required
Function called when the command is selected. Receives the editor instance and the range to replace.

Using individual commands

You can cherry-pick from the default commands to show only specific options:
import { BUTTON, SlashCommand } from '@react-email/editor/ui';

<SlashCommand.Root items={[BUTTON]} />
This is useful when you want a minimal command palette — for example, only allowing button insertion.

Controlling visibility

char
string
default:"/"
Character that triggers the command menu.
allow
(props: { editor }) => boolean
Function to control when the command menu can appear. Return false to prevent it.
<SlashCommand.Root
  items={defaultSlashCommands}
  char="/"
  allow={({ editor }) => !editor.isActive('codeBlock')}
/>