ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β π shadcn/directory/udecode/plate/(guides)/editor β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β
This guide covers the configuration options for the Plate editor, including basic setup, plugin management, and advanced configuration techniques.
To create a basic Plate editor, you can use the createPlateEditor function, or usePlateEditor in a React component:
import { createPlateEditor } from 'platejs/react';
const editor = createPlateEditor({
plugins: [HeadingPlugin],
});
Set the initial content of the editor:
const editor = createPlateEditor({
value: [
{
type: 'p',
children: [{ text: 'Hello, Plate!' }],
},
],
});
You can also initialize the editor with an HTML string and the associated plugins:
const editor = createPlateEditor({
plugins: [BoldPlugin, ItalicPlugin],
value: '<p>This is <b>bold</b> and <i>italic</i> text!</p>',
});
For a comprehensive list of plugins that support HTML string deserialization, refer to the Plugin Deserialization Rules section.
If you need to fetch the initial value asynchronously (e.g., from an API), you can pass an async function directly to the value option:
function AsyncEditor() {
const editor = usePlateEditor({
value: async () => {
// Simulate fetching data from an API
const response = await fetch('/api/document');
const data = await response.json();
return data.content;
},
autoSelect: 'end',
onReady: ({ editor, value }) => {
console.info('Editor ready with loaded value:', value);
},
});
if (!editor.children.length) return <div>Loadingβ¦</div>;
return (
<Plate editor={editor}>
<EditorContainer>
<Editor />
</EditorContainer>
</Plate>
);
}
You can add plugins to your editor by including them in the plugins array:
const editor = createPlateEditor({
plugins: [HeadingPlugin, ListPlugin],
});
Set the maximum length of the editor:
const editor = createPlateEditor({
maxLength: 100,
});
Set a custom id for the editor:
const editor = createPlateEditor({
id: 'my-custom-editor-id',
});
If defined, you should always pass the id as the first argument in any editor retrieval methods.
Plate includes a built-in system for automatically assigning unique IDs to nodes, which is crucial for certain plugins and for data persistence strategies that rely on stable identifiers.
This feature is enabled by default. You can customize its behavior or disable it entirely through the nodeId option.
To configure Node ID behavior, pass an object to the nodeId property when creating your editor:
const editor = usePlateEditor({
// ... other plugins and options
nodeId: {
// Function to generate IDs (default: nanoid(10))
idCreator: () => uuidv4(),
// Exclude inline elements from getting IDs (default: true)
filterInline: true,
// Exclude text nodes from getting IDs (default: true)
filterText: true,
// Reuse IDs on undo/redo and copy/paste if not in document (default: false)
// Set to true if IDs should be stable across such operations.
reuseId: false,
// Normalize all nodes in initial value (default: false - only checks first/last)
// Set to true to ensure all initial nodes get IDs if missing.
normalizeInitialValue: false,
// Prevent overriding IDs when inserting nodes with an existing id (default: false)
disableInsertOverrides: false,
// Only allow specific node types to receive IDs (default: all)
allow: ['p', 'h1'],
// Exclude specific node types from receiving IDs (default: [])
exclude: ['code_block'],
// Custom filter function to determine if a node should get an ID
filter: ([node, path]) => {
// Example: Only ID on top-level blocks
return path.length === 1;
},
},
});
<Callout type="note">
The `NodeIdPlugin` (which handles this) is part of the core plugins and is automatically included. You only need to specify the `nodeId` option if you want to customize its default behavior.
</Callout>
If you don't need automatic node IDs, you can disable the feature:
const editor = usePlateEditor({
// ... other plugins and options
nodeId: false, // This will disable the NodeIdPlugin
});
By disabling this, certain plugins that rely on node IDs will not function properly. The following plugins require block IDs to work:
Control whether the editor should normalize its content on initialization:
const editor = createPlateEditor({
shouldNormalizeEditor: true,
});
Note that normalization may take a few dozen milliseconds for large documents, such as the playground value.
Configure the editor to automatically select a range:
const editor = createPlateEditor({
autoSelect: 'end', // or 'start', or true
});
This is not the same as auto-focus: you can select text without focusing the editor.
Override default components for plugins:
const editor = createPlateEditor({
plugins: [HeadingPlugin],
components: {
[ParagraphPlugin.key]: CustomParagraphComponent,
[HeadingPlugin.key]: CustomHeadingComponent,
},
});
Override specific plugin configurations:
const editor = createPlateEditor({
plugins: [HeadingPlugin],
override: {
plugins: {
[ParagraphPlugin.key]: {
options: {
customOption: true,
},
},
},
},
});
Disable specific plugins:
const editor = createPlateEditor({
plugins: [HeadingPlugin, ListPlugin],
override: {
enabled: {
[HistoryPlugin.key]: false,
},
},
});
You can override core plugins or previously defined plugins by adding a plugin with the same key. The last plugin with a given key wins:
const CustomParagraphPlugin = createPlatePlugin({
key: 'p',
// Custom implementation
});
const editor = createPlateEditor({
plugins: [CustomParagraphPlugin],
});
From the root plugin, you can configure any plugin:
const editor = createPlateEditor({
plugins: [HeadingPlugin],
rootPlugin: (plugin) =>
plugin.configurePlugin(LengthPlugin, {
options: {
maxLength: 100,
},
}),
});
createPlateEditor will automatically infer the types for your editor from the value and the plugins you pass in. For explicit type creation, use the generics:
const editor = createPlateEditor<Value, typeof TablePlugin | typeof LinkPlugin>({
plugins: [TablePlugin, LinkPlugin],
});
// Usage
editor.tf.insert.tableRow()
For more complex editors, you can define your types in a separate file (e.g., plate-types.ts):
import type { TElement, TText } from 'platejs';
import type { TPlateEditor } from 'platejs/react';
// Define custom element types
interface ParagraphElement extends TElement {
align?: 'left' | 'center' | 'right' | 'justify';
children: RichText[];
type: typeof ParagraphPlugin.key;
}
interface ImageElement extends TElement {
children: [{ text: '' }]
type: typeof ImagePlugin.key;
url: string;
}
// Define custom text types
interface FormattedText extends TText {
bold?: boolean;
italic?: boolean;
}
export type MyRootBlock = ParagraphElement | ImageElement;
// Define the editor's value type
export type MyValue = MyRootBlock[];
// Define the custom editor type
export type MyEditor = TPlateEditor<MyValue, typeof TablePlugin | typeof LinkPlugin>;
export const useMyEditorRef = () => useEditorRef<MyEditor>();
// Usage
const value: MyValue = [{
type: 'p',
children: [{ text: 'Hello, Plate!' }],
}]
const editorInferred = createPlateEditor({
plugins: [TablePlugin, LinkPlugin],
value,
});
// or
const editorExplicit = createPlateEditor<MyValue, typeof TablePlugin | typeof LinkPlugin>({
plugins: [TablePlugin, LinkPlugin],
value,
});
β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ