Plate
PlateEditorsTemplates
GitHub16kGitHub
DiscordDiscord
    • Stream
    • Copilot
  • Comments
  • Discussion
  • Suggestions
    • Basic Blocks
      • Blockquote
      • Heading
      • Horizontal Rule
    • Callout
    • Code Block
    • Column
    • Date
    • Equation
    • Link
    • Media
    • MentionElement
    • Table
    • Table of Contents
    • Footnote
    • Details
  • 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
    • Drag & Drop
    • Navigation Feedback
    • Linting
    • Tabbable
    • Toolbar
    • Yjs
    • Multi SelectEditor
    • DOCX
    • HTML
    • Markdown

Exit Break

PreviousNext

Exit a large block using a shortcut.

Loading…
ListSingle Block

On This Page

FeaturesKit usageInstallationAdd kitManual usageAdd pluginConfigure pluginKeyboard shortcutsPluginsExitBreakPluginHow exit break worksExit point determinationExamplesCustom plugin configuration
Build your editor
Production-ready AI template and reusable components.
Get all-access

Features

  • Exit from nested block structures (like code blocks, tables, columns) using keyboard shortcuts.
  • Leaves only the nearest structure, so Mod+Enter in a code block, callout, image or divider inside a column inserts the new block in that column.
  • Inserts the block the surrounding container declares as its default, such as a paragraph in a column.
Report an issue

Kit usage

Installation

The fastest way to add exit break functionality is with the ExitBreakKit, which includes pre-configured ExitBreakPlugin with keyboard shortcuts.

'use client';
 
import { ExitBreakPlugin } from 'platejs';
 
export const ExitBreakKit = [
  ExitBreakPlugin.configure({
    shortcuts: {
      insert: { keys: 'mod+enter' },
      insertBefore: { keys: 'mod+shift+enter' },
    },
  }),
];
'use client';
 
import { ExitBreakPlugin } from 'platejs';
 
export const ExitBreakKit = [
  ExitBreakPlugin.configure({
    shortcuts: {
      insert: { keys: 'mod+enter' },
      insertBefore: { keys: 'mod+shift+enter' },
    },
  }),
];

Add kit

import { createEditor } from 'platejs/react';
import { ExitBreakKit } from '@/components/editor/exit-break';
 
const editor = createEditor({
  plugins: [
    // ...otherPlugins,
    ...ExitBreakKit,
  ],
});
import { createEditor } from 'platejs/react';
import { ExitBreakKit } from '@/components/editor/exit-break';
 
const editor =




Manual usage

Add plugin

import { ExitBreakPlugin } from 'platejs';
import { createEditor } from 'platejs/react';
 
const editor = createEditor({
  plugins: [
    // ...otherPlugins,
    ExitBreakPlugin,
  ],
});
import { ExitBreakPlugin } from 'platejs';
import { createEditor } from 'platejs/react';
 
const editor = createEditor({
  plugins: [
    // ...otherPlugins,
    ExitBreakPlugin,
  ],
});

Configure plugin

import { ExitBreakPlugin } from 'platejs';
import { createEditor } from 'platejs/react';
 
const editor = createEditor({
  plugins: [
    // ...otherPlugins,
    ExitBreakPlugin.configure({
      shortcuts: {
        insert: { keys: 'mod+enter' },
        insertBefore: { keys: 'mod+shift+enter' },
      },
    }),
  ],
});













  • shortcuts.insert: Defines a keyboard shortcut to exit and insert block after.
  • shortcuts.insertBefore: Defines a keyboard shortcut to exit and insert block before.

Keyboard shortcuts

KeyDescription
Cmd + Enter

Exit the current block structure and insert a new block after.

Cmd + Shift + Enter

Exit the current block structure and insert a new block before.

Plugins

ExitBreakPlugin

Provides shortcuts that leave the current block structure through tx.break.exit.

Options

    Keyboard shortcuts configuration.

How exit break works

Exit break leaves the nearest structure around the caret. A code block, callout, image or divider is a structure of its own, so exit inserts the new block right after it, inside the same container. From any other block, exit leaves the nearest container that can take a paragraph beside it: a paragraph in a quote leaves the quote, and a paragraph in a column leaves the whole column group, because the group holds only columns. The new block is the default that the structure's parent declares.

Exit point determination

When you trigger exit break:

  1. Starts from the block that holds the caret
  2. Stops at that block when it owns its exit: a void such as a divider, an object such as an image, or a text block that declares ownsExit, such as a code block or a callout
  3. Otherwise walks up its ancestors and stops at the first one that sits directly in the document, or whose parent can hold a text block such as a paragraph
  4. Inserts that parent's default block next to the exit point and moves the caret into it

Exit passes over a block that owns its exit, and leaves the container instead, when its parent cannot put a plain text block beside it. That happens when the parent has no room or no default block, or when its default needs a property nothing supplies, holds no text, or owns its exit too. Below the top level, the walk also passes a container whose default would put the caret back into a container of the same type.

Once exit stops at a container, it never climbs further. When that container's parent declares no default block, has no room for another one, or has a default that needs a property nothing supplies or holds no text, nothing changes.

Examples

Code Block:

<codeBlock>                              // ← Exit point (top-level block)
  code|                                  // ← Starting position
</codeBlock>
<paragraph>|</paragraph>                 // ← New paragraph inserted here
<codeBlock>                              // ← Exit point (top-level block)
  code|                                  // ← Starting position
</codeBlock>
<paragraph>|</paragraph>                 // ← New paragraph inserted here

Code Block in Column (stays in the column):

<columnGroup>
  <column>
    <codeBlock>                          // ← Exit point (owns its exit)
      code|                              // ← Starting position
    </codeBlock>
    <paragraph>|</paragraph>             // ← New paragraph inserted here
  </column>
</columnGroup>
<columnGroup>
  <column>
    <codeBlock>                          // ← Exit point (owns its exit)
      code|                              // ← Starting position
    </codeBlock>
    <paragraph>|</paragraph>             // ← New paragraph inserted here
  </column>
</columnGroup>

Image or Divider in Column:

<columnGroup>
  <column>
    <image url="...">caption|</image>    // ← Exit point and starting position
    <paragraph>|</paragraph>             // ← New paragraph inserted here
  </column>
</columnGroup>
<columnGroup>
  <column>
    <image url="...">caption|</image>    // ← Exit point and starting position
    <paragraph>|</paragraph>             // ← New paragraph inserted here
  </column>
</columnGroup>

Paragraph in Column (leaves the column group):

<columnGroup>                            // ← Exit point (top-level block)
  <column>                               // group allows columns only
    <paragraph>content|</paragraph>      // ← Starting position
  </column>
</columnGroup>
<paragraph>|</paragraph>                 // ← New paragraph inserted here
<columnGroup>                            // ← Exit point (top-level block)
  <column>                               // group allows columns only
    <paragraph>content|</paragraph>      // ← Starting position
  </column>
</columnGroup>
<paragraph>|</paragraph>                 // ← New paragraph inserted here

Table in Column (exits at table level):

// First exit
<columnGroup>
  <column>                               
    <table>                              // ← Exit point (column allows blocks)
      <tableRow>                         // table allows rows only
        <tableCell>                      // row allows cells only
          <paragraph>content|</paragraph>// ← Starting position
        </tableCell>
      </tableRow>
    </table>
    <paragraph>|</paragraph>             // ← New paragraph inserted here
  </column>
</columnGroup>
 
// Second exit
<columnGroup>                            // ← Exit point (top-level block)
  <column>                               // group allows columns only
    <table>                              
      <tableRow>
        <tableCell>
          <paragraph>content</paragraph>
        </tableCell>
      </tableRow>
    </table>
    <paragraph>|</paragraph>             // ← Starting position
  </column>
</columnGroup>
<paragraph>|</paragraph>                 // ← New paragraph inserted here
// First exit
<columnGroup>
  <column>                               
    <table>                              // ← Exit point (column allows blocks)
      <tableRow>                         // table allows rows only
        <tableCell>                      // row allows cells only
          <paragraph>content|</paragraph>// ← Starting position
        </tableCell>
      </tableRow>
    </table>
    <paragraph>|</paragraph>             // ← New paragraph inserted here
  </column>
</columnGroup>
 
// Second exit
<columnGroup>                            // ← Exit point (top-level block)
  <










Custom plugin configuration

Declare each custom element's allowed child content and its default. An exit passes ancestors whose parent cannot hold a paragraph, such as a cell in a row, and inserts the default that the landing parent declares:

import { definePlugin, schema } from 'platejs';
 
// Table structure
const CustomTablePlugin = definePlugin('table', {
  schema: {
    element: {
      content: schema.content.type('tr', { min: 1 }),
    },
  },
});
 
const CustomTableRowPlugin = definePlugin('tr', {
  schema: {
    element: {
      content: schema.content.types(['td', 'th'], {
        default: { type: 'td' },
        min: 1,
      }),
    },
  },
});
 
const CustomTableCellPlugin = definePlugin('td', {
  schema: {
    element: {
      content: schema.content.group('block', {
        default: { type: 'paragraph' },
        min: 1,
      }),
    },
  },
});
import { definePlugin, schema } from 'platejs';
 
// Table structure
const CustomTablePlugin = definePlugin('table', {
  schema: {
    element: {
      content: schema.content.type('tr', { min: 1 }),
    },
  },
});
 
const CustomTableRowPlugin = definePlugin('tr', {
  schema: {
    element: {
      content: schema.content.types(['td', 'th'], {
        default: { type: 'td' },
        min: 1,
      }),
    },












A text block that exit should leave before its container, such as a custom code-like block or a callout whose Enter rule exits, declares ownsExit. Without it, the block behaves like a paragraph and exit leaves its container:

import { definePlugin, schema } from 'platejs';
 
const NoticePlugin = definePlugin('notice', {
  rules: { break: { emptyLineEnd: 'deleteExit' } },
  schema: {
    element: schema.element.textBlock({ ownsExit: true }),
  },
});
import { definePlugin, schema } from 'platejs';
 
const NoticePlugin = definePlugin('notice', {
  rules: { break: { emptyLineEnd: 'deleteExit' } },
  schema: {
    element: schema.element.textBlock({ ownsExit: true }),
  },
});

Only a text block can declare ownsExit. Voids and objects always own their exit.

createEditor
({
plugins: [
// ...otherPlugins,
...ExitBreakKit,
],
});
import { ExitBreakPlugin } from 'platejs';
import { createEditor } from 'platejs/react';
const editor = createEditor({
plugins: [
// ...otherPlugins,
ExitBreakPlugin.configure({
shortcuts: {
insert: { keys: 'mod+enter' },
insertBefore: { keys: 'mod+shift+enter' },
},
}),
],
});
column
> // group allows columns only
<table>
<tableRow>
<tableCell>
<paragraph>content</paragraph>
</tableCell>
</tableRow>
</table>
<paragraph>|</paragraph> // ← Starting position
</column>
</columnGroup>
<paragraph>|</paragraph> // ← New paragraph inserted here
},
});
const CustomTableCellPlugin = definePlugin('td', {
schema: {
element: {
content: schema.content.group('block', {
default: { type: 'paragraph' },
min: 1,
}),
},
},
});