'use client';
import * as React from 'react';
import { Plate, usePlateEditor } from 'platejs/react';
import { EditorKit } from '@/components/editor/editor-kit';
import { Editor, EditorContainer } from '@/components/ui/editor';
import { DEMO_VALUES } from './values/demo-values';
export default function Demo({ id }: { id: string }) {
const editor = usePlateEditor({
plugins: EditorKit,
value: DEMO_VALUES[id],
});
return (
<Plate editor={editor}>
<EditorContainer variant="demo">
<Editor />
</EditorContainer>
</Plate>
);
}
Features
- Markdown-style shortcuts for blocks (e.g.,
#
to H1,>
for blockquote). - Inline mark formatting (e.g.,
**bold**
,*italic*
,~~strikethrough~~
). - Smart punctuation conversion (e.g.,
--
to—
,...
to…
). - Mathematical symbols and fractions.
- Legal symbols and arrows.
- Undo support on delete to reverse autoformatting.
Kit Usage
Installation
The fastest way to add autoformatting is with the AutoformatKit
, which includes comprehensive formatting rules for blocks, marks, and text replacements.
'use client';
import type { AutoformatRule } from '@platejs/autoformat';
import {
autoformatArrow,
autoformatLegal,
autoformatLegalHtml,
autoformatMath,
AutoformatPlugin,
autoformatPunctuation,
autoformatSmartQuotes,
} from '@platejs/autoformat';
import { insertEmptyCodeBlock } from '@platejs/code-block';
import { toggleList } from '@platejs/list';
import { KEYS } from 'platejs';
const autoformatMarks: AutoformatRule[] = [
{
match: '***',
mode: 'mark',
type: [KEYS.bold, KEYS.italic],
},
{
match: '__*',
mode: 'mark',
type: [KEYS.underline, KEYS.italic],
},
{
match: '__**',
mode: 'mark',
type: [KEYS.underline, KEYS.bold],
},
{
match: '___***',
mode: 'mark',
type: [KEYS.underline, KEYS.bold, KEYS.italic],
},
{
match: '**',
mode: 'mark',
type: KEYS.bold,
},
{
match: '__',
mode: 'mark',
type: KEYS.underline,
},
{
match: '*',
mode: 'mark',
type: KEYS.italic,
},
{
match: '_',
mode: 'mark',
type: KEYS.italic,
},
{
match: '~~',
mode: 'mark',
type: KEYS.strikethrough,
},
{
match: '^',
mode: 'mark',
type: KEYS.sup,
},
{
match: '~',
mode: 'mark',
type: KEYS.sub,
},
{
match: '==',
mode: 'mark',
type: KEYS.highlight,
},
{
match: '≡',
mode: 'mark',
type: KEYS.highlight,
},
{
match: '`',
mode: 'mark',
type: KEYS.code,
},
];
const autoformatBlocks: AutoformatRule[] = [
{
match: '# ',
mode: 'block',
type: KEYS.h1,
},
{
match: '## ',
mode: 'block',
type: KEYS.h2,
},
{
match: '### ',
mode: 'block',
type: KEYS.h3,
},
{
match: '#### ',
mode: 'block',
type: KEYS.h4,
},
{
match: '##### ',
mode: 'block',
type: KEYS.h5,
},
{
match: '###### ',
mode: 'block',
type: KEYS.h6,
},
{
match: '> ',
mode: 'block',
type: KEYS.blockquote,
},
{
match: '```',
mode: 'block',
type: KEYS.codeBlock,
format: (editor) => {
insertEmptyCodeBlock(editor, {
defaultType: KEYS.p,
insertNodesOptions: { select: true },
});
},
},
// {
// match: '+ ',
// mode: 'block',
// preFormat: openNextToggles,
// type: KEYS.toggle,
// },
{
match: ['---', '—-', '___ '],
mode: 'block',
type: KEYS.hr,
format: (editor) => {
editor.tf.setNodes({ type: KEYS.hr });
editor.tf.insertNodes({
children: [{ text: '' }],
type: KEYS.p,
});
},
},
];
const autoformatLists: AutoformatRule[] = [
{
match: ['* ', '- '],
mode: 'block',
type: 'list',
format: (editor) => {
toggleList(editor, {
listStyleType: KEYS.ul,
});
},
},
{
match: [String.raw`^\d+\.$ `, String.raw`^\d+\)$ `],
matchByRegex: true,
mode: 'block',
type: 'list',
format: (editor, { matchString }) => {
toggleList(editor, {
listRestartPolite: Number(matchString) || 1,
listStyleType: KEYS.ol,
});
},
},
{
match: ['[] '],
mode: 'block',
type: 'list',
format: (editor) => {
toggleList(editor, {
listStyleType: KEYS.listTodo,
});
editor.tf.setNodes({
checked: false,
listStyleType: KEYS.listTodo,
});
},
},
{
match: ['[x] '],
mode: 'block',
type: 'list',
format: (editor) => {
toggleList(editor, {
listStyleType: KEYS.listTodo,
});
editor.tf.setNodes({
checked: true,
listStyleType: KEYS.listTodo,
});
},
},
];
export const AutoformatKit = [
AutoformatPlugin.configure({
options: {
enableUndoOnDelete: true,
rules: [
...autoformatBlocks,
...autoformatMarks,
...autoformatSmartQuotes,
...autoformatPunctuation,
...autoformatLegal,
...autoformatLegalHtml,
...autoformatArrow,
...autoformatMath,
...autoformatLists,
].map(
(rule): AutoformatRule => ({
...rule,
query: (editor) =>
!editor.api.some({
match: { type: editor.getType(KEYS.codeBlock) },
}),
})
),
},
}),
];
Add Kit
import { createPlateEditor } from 'platejs/react';
import { AutoformatKit } from '@/components/editor/plugins/autoformat-kit';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
...AutoformatKit,
],
});
Manual Usage
Installation
pnpm add @platejs/autoformat
Add Plugin
import { AutoformatPlugin } from '@platejs/autoformat';
import { createPlateEditor } from 'platejs/react';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
AutoformatPlugin,
],
});
Configure Plugin
Configure autoformat with custom rules:
import { AutoformatPlugin } from '@platejs/autoformat';
AutoformatPlugin.configure({
options: {
rules: [
// Block rules
{
match: '# ',
mode: 'block',
type: 'h1',
},
{
match: '> ',
mode: 'block',
type: 'blockquote',
},
// Mark rules
{
match: '**',
mode: 'mark',
type: 'bold',
},
{
match: '*',
mode: 'mark',
type: 'italic',
},
],
enableUndoOnDelete: true,
},
});
Advanced Configuration
Import predefined rule sets for comprehensive autoformatting:
import { AutoformatPlugin } from '@platejs/autoformat';
import {
autoformatArrow,
autoformatLegal,
autoformatMath,
autoformatPunctuation,
autoformatSmartQuotes,
} from '@platejs/autoformat';
AutoformatPlugin.configure({
options: {
enableUndoOnDelete: true,
rules: [
// Custom block rules
{
match: '# ',
mode: 'block',
type: 'h1',
},
// Predefined rule sets
...autoformatSmartQuotes,
...autoformatPunctuation,
...autoformatArrow,
...autoformatLegal,
...autoformatMath,
].map((rule) => ({
...rule,
// Disable autoformat in code blocks
query: (editor) =>
!editor.api.some({
match: { type: 'code_block' },
}),
})),
},
});
rules
: Array of autoformat rules defining triggers and formatting actions.enableUndoOnDelete
: Allows undoing autoformat by pressing backspace.query
: Function to conditionally enable/disable rules based on context.
Using Regex Patterns
For more complex matching patterns, you can use regular expressions:
import { AutoformatPlugin } from '@platejs/autoformat';
import { toggleList } from '@platejs/list';
AutoformatPlugin.configure({
options: {
rules: [
{
match: [String.raw`^\d+\.$ `, String.raw`^\d+\)$ `],
matchByRegex: true,
mode: 'block',
type: 'list',
format: (editor, { matchString }) => {
const number = Number(matchString.match(/\d+/)?.[0]) || 1;
toggleList(editor, {
listRestartPolite: number,
listStyleType: 'ol',
});
},
},
],
},
});
matchByRegex
: Enables regex pattern matching instead of string equality.- Note that Regex patterns only work with
mode: 'block'
and are applied at block start (triggerAtBlockStart: true
).
Plugins
AutoformatPlugin
Plugin for automatic text formatting based on typing patterns.
Predefined Rules
You can import the following predefined rule sets:
Name | Description |
---|---|
autoformatSmartQuotes | Converts "text" to "text" . |
Converts 'text' to 'text' . | |
autoformatPunctuation | Converts -- to — . |
Converts ... to … . | |
Converts >> to » . | |
Converts << to « . | |
autoformatArrow | Converts -> to → . |
Converts <- to ← . | |
Converts => to ⇒ . | |
Converts <= and ≤= to ⇐ . | |
autoformatLegal | Converts (tm) and (TM) to ™ . |
Converts (r) and (R) to ® . | |
Converts (c) and (C) to © . | |
autoformatLegalHtml | Converts ™ to ™ . |
Converts ® to ® . | |
Converts © to © . | |
Converts § to § . | |
autoformatComparison | Converts !> to ≯ . |
Converts !< to ≮ . | |
Converts >= to ≥ . | |
Converts <= to ≤ . | |
Converts !>= to ≱ . | |
Converts !<= to ≰ . | |
autoformatEquality | Converts != to ≠ . |
Converts == to ≡ . | |
Converts !== and ≠= to ≢ . | |
Converts ~= to ≈ . | |
Converts !~= to ≉ . | |
autoformatFraction | Converts 1/2 to ½ . |
Converts 1/3 to ⅓ . | |
... | |
Converts 7/8 to ⅞ . | |
autoformatDivision | Converts // to ÷ . |
autoformatOperation | Converts +- to ± . |
Converts %% to ‰ . | |
Converts %%% and ‰% to ‱ . | |
autoformatDivision rules. | |
autoformatSubscriptNumbers | Converts ~0 to ₀ . |
Converts ~1 to ₁ . | |
... | |
Converts ~9 to ₉ . | |
autoformatSubscriptSymbols | Converts ~+ to ₊ . |
Converts ~- to ₋ . | |
autoformatSuperscriptNumbers | Converts ^0 to ⁰ . |
Converts ^1 to ¹ . | |
... | |
Converts ^9 to ⁹ . | |
autoformatSuperscriptSymbols | Converts ^+ to ⁺ . |
Converts ^- to ⁻ . | |
autoformatMath | autoformatComparison rules |
autoformatEquality rules | |
autoformatOperation rules | |
autoformatFraction rules | |
autoformatSubscriptNumbers rules | |
autoformatSubscriptSymbols rules | |
autoformatSuperscriptNumbers rules | |
autoformatSuperscriptSymbols rules |
Types
AutoformatCommonRule
An interface for the common structure of autoformat rules, regardless of their mode.
- For
mode: 'block'
: lookup for the end match(es) before the cursor. - For
mode: 'text'
: lookup for the end match(es) before the cursor. Ifformat
is an array, also lookup for the start match(es). - For
mode: 'mark'
: lookup for the start and end matches. - Note:
'_*'
,['_*']
and{ start: '_*', end: '*_' }
are equivalent. MatchRange
:- Default:
false
The rule applies when the trigger and the text just before the cursor matches.
Triggering character to autoformat.
If true, insert the triggering character after autoformatting.
AutoformatBlockRule
An interface for autoformat rules for block mode.
- Default:
true
- Default:
false
Block mode: set block type or custom format.
Pattern to match for the autoformat rule.
For mode: 'block'
: set block type. If format
is defined, this field is ignored.
Whether trigger should be at block start.
Whether to allow autoformat with same block type above.
Function called before format
. Used to reset selected block.
Custom formatting function.
AutoformatMarkRule
An interface for autoformat rules for mark mode.
AutoformatTextRule
An interface for autoformat rules for text mode.