Plugin components are the React rendering layer for Plate node plugins. Use
Plate UI components first when the registry already has the node you need, then
customize with EditorElement or EditorLeaf and bind it through
.configure({ component }). This page shows the one component binding path.
Plate UI components are copied into your app. That makes them the fastest path for production styling and the safest starting point for customization.
| Start here | Use when |
|---|---|
| Plate UI | You want registry components copied into your app. |
| Feature Kits |
| You want plugin groups that already wire components, shortcuts, and options. |
| This page | You are writing or replacing a component by hand. |
The package owns plugin behavior. Your app owns copied component files and their styles.
Use EditorElement for element nodes and EditorLeaf for mark or leaf nodes.
Both components merge editor attributes and node props, className, and
style onto the rendered DOM element.
Always render children. Plate needs the children in the DOM even when the
element is void or the visible UI comes from surrounding controls.
Element components render block, inline, and void element nodes.
'use client';
import type { BlockquotePlugin } from 'platejs/react';
import { type EditorElementProps, EditorElement } from 'platejs/react';
export function BlockquoteElement({
children,
...props
}: EditorElementProps<typeof BlockquotePlugin>) {
return (
<EditorElement
as="blockquote"
className="my-1 border-l-2 pl-6 italic"
{...props}
>
{children}
</EditorElement>
);
}'use client';
import type { BlockquotePlugin } from 'platejs/react';
import { type EditorElementProps, EditorElement } from 'platejs/react';
export function BlockquoteElement({
children,
...props
}: EditorElementProps<typeof BlockquotePlugin>) {
return (
<EditorElement
as="blockquote"
className="my-1 border-l-2 pl-6 italic"
{...props}
>
{children}
</EditorElement>
);
}EditorElement renders a div by default. Pass as when the node should render
as a specific HTML element.
Leaf components render marked and decorated text ranges.
'use client';
import type { CodePlugin } from 'platejs/react';
import { type EditorLeafProps, EditorLeaf } from 'platejs/react';
export function CodeLeaf({
children,
...props
}: EditorLeafProps<typeof CodePlugin>) {
return (
<EditorLeaf
as="code"
className="whitespace-pre-wrap rounded-md bg-muted px-[0.3em] py-[0.2em] font-mono text-sm"
{...props}
>
{children}
</EditorLeaf>
);
}'use client';
import type { CodePlugin } from 'platejs/react';
import { type EditorLeafProps, EditorLeaf } from 'platejs/react';
export function CodeLeaf({
children,
...props
}: EditorLeafProps<typeof CodePlugin>) {
return (
<EditorLeaf
as="code"
className="whitespace-pre-wrap rounded-md bg-muted px-[0.3em] py-[0.2em] font-mono text-sm"
{...props}
>
{children}
</EditorLeaf>
);
}EditorLeaf renders a span by default. Use it for plugins that declare
schema.mark.
Declare component in a new Plate plugin, or include it in the existing
descriptor's single terminal .configure() call.
Use .configure({ component }) to attach a React component to a plugin.
import {
BlockquotePlugin,
CodePlugin,
} from 'platejs/react';
import { BlockquoteElement } from '@/components/editor/blockquote';
import { CodeLeaf } from '@/components/editor/code';
export const plugins = [
BlockquotePlugin.configure({ component: BlockquoteElement }),
CodePlugin.configure({ component: CodeLeaf }),
];import {
BlockquotePlugin,
CodePlugin,
} from 'platejs/react';
import { BlockquoteElement } from '@/components/editor/blockquote';
import { CodeLeaf } from '@/components/editor/code';
export const plugins = [
BlockquotePlugin.configure({ component: BlockquoteElement }),
CodePlugin.configure({ component: CodeLeaf }),
];When the same plugin also needs rules, shortcuts, initial state, or input rules,
put every override in that same terminal .configure() call.
import { CodeRules } from 'platejs';
import { CodePlugin } from 'platejs/react';
import { CodeLeaf } from '@/components/editor/code';
export const plugins = [
CodePlugin.configure({
component: CodeLeaf,
inputRules: [CodeRules.markdown()],
shortcuts: { toggle: { keys: 'mod+e' } },
}),
];import { CodeRules } from 'platejs';
import { CodePlugin } from 'platejs/react';
import { CodeLeaf } from '@/components/editor/code';
export const plugins = [
CodePlugin.configure({
component: CodeLeaf,
inputRules: [CodeRules.markdown()],
shortcuts: { toggle: { keys: 'mod+e' } },
}),
];Bind an HTML tag directly when the default EditorElement or EditorLeaf
behavior is enough.
import { schema } from 'platejs';
import { definePlugin } from 'platejs/react';
export const QuotePlugin = definePlugin('quote', {
component: 'blockquote',
schema: {
element: { content: schema.content.text({ default: 'text', min: 1 }) },
},
});import { schema } from 'platejs';
import { definePlugin } from 'platejs/react';
export const QuotePlugin = definePlugin('quote', {
component: 'blockquote',
schema: {
element: { content: schema.content.text({ default: 'text', min: 1 }) },
},
});Reach for a custom component once you need classes, nested controls, popovers, toolbars, resize handles, or plugin state inside the render tree.
Prefer component-local styles. Plate also adds a editor-<node-type> class while
rendering plugin nodes, so global CSS can target stable node types when you need
editor-wide styling.
.editor-paragraph {
margin-block: 0.25rem;
}
.editor-code {
border-radius: 0.375rem;
font-family: var(--font-mono);
}.editor-paragraph {
margin-block: 0.25rem;
}
.editor-code {
border-radius: 0.375rem;
font-family: var(--font-mono);
}Use global selectors sparingly. Component files are easier to copy, inspect, and replace from the registry.
| API | Use for | Notes |
|---|---|---|
EditorElement | Element nodes. | Defaults to div; accepts as, className, style, and Plate render props. |
EditorLeaf | Marked and decorated text. | Defaults to span; use with plugins that declare schema.mark. |
plugin.configure({ component: Component }) | Ordinary node component binding. | Include the component and every consumer override in the same terminal call. |
plugin.configure({ component: 'tag' }) | Default wrapper with an intrinsic tag. | Accepts an HTML tag such as 'blockquote', 'strong', or 'code'. |
For plugin method details, see Plugin Methods. For static rendering components, see Static Rendering.