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 PlateElement, PlateLeaf, .configure({ component }), or the editor
components map. This page shows which registration path to use.
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. |
| 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 PlateElement for element nodes and PlateLeaf for mark or leaf nodes.
Both components merge Plite attributes, Plate node props, className, and
style onto the rendered DOM element.
Always render children. Plite 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/basic-nodes/react';
import { type PlateElementProps, PlateElement } from 'platejs/react';
export function BlockquoteElement({
children,
...props
}: PlateElementProps<typeof BlockquotePlugin>) {
return (
<PlateElement
as="blockquote"
className="my-1 border-l-2 pl-6 italic"
{...props}
>
{children}
</PlateElement>
);
}'use client';
import type { BlockquotePlugin } from '@platejs/basic-nodes/react';
import { type PlateElementProps, PlateElement } from 'platejs/react';
export function BlockquoteElement({
children,
...props
}: PlateElementProps<typeof BlockquotePlugin>) {
return (
<PlateElement
as="blockquote"
className="my-1 border-l-2 pl-6 italic"
{...props}
>
{children}
</PlateElement>
);
}PlateElement 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/basic-nodes/react';
import { type PlateLeafProps, PlateLeaf } from 'platejs/react';
export function CodeLeaf({
children,
...props
}: PlateLeafProps<typeof CodePlugin>) {
return (
<PlateLeaf
as="code"
className="whitespace-pre-wrap rounded-md bg-muted px-[0.3em] py-[0.2em] font-mono text-sm"
{...props}
>
{children}
</PlateLeaf>
);
}'use client';
import type { CodePlugin } from '@platejs/basic-nodes/react';
import { type PlateLeafProps, PlateLeaf } from 'platejs/react';
export function CodeLeaf({
children,
...props
}: PlateLeafProps<typeof CodePlugin>) {
return (
<PlateLeaf
as="code"
className="whitespace-pre-wrap rounded-md bg-muted px-[0.3em] py-[0.2em] font-mono text-sm"
{...props}
>
{children}
</PlateLeaf>
);
}PlateLeaf 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/basic-nodes/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/basic-nodes/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/basic-nodes';
import { CodePlugin } from '@platejs/basic-nodes/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/basic-nodes';
import { CodePlugin } from '@platejs/basic-nodes/react';
import { CodeLeaf } from '@/components/editor/code';
export const plugins = [
CodePlugin.configure({
component: CodeLeaf,
inputRules: [CodeRules.markdown()],
shortcuts: { toggle: { keys: 'mod+e' } },
}),
];Use the editor components option when a single editor owns the component map.
This is useful for replacing several components in one place.
import {
BlockquotePlugin,
CodePlugin,
} from '@platejs/basic-nodes/react';
import { Plate, usePlateEditor } from 'platejs/react';
import { BlockquoteElement } from '@/components/editor/blockquote';
import { CodeLeaf } from '@/components/editor/code';
import { Editor, EditorContainer } from '@/components/editor/editor';
export function AppEditor() {
const editor = usePlateEditor({
components: {
blockquote: BlockquoteElement,
code: CodeLeaf,
},
plugins: [BlockquotePlugin, CodePlugin],
});
return (
<Plate editor={editor}>
<EditorContainer>
<Editor />
</EditorContainer>
</Plate>
);
}import {
BlockquotePlugin,
CodePlugin,
} from '@platejs/basic-nodes/react';
import { Plate, usePlateEditor } from 'platejs/react';
import { BlockquoteElement } from '@/components/editor/blockquote';
import { CodeLeaf } from '@/components/editor/code';
import { Editor, EditorContainer } from '@/components/editor/editor';
export function AppEditor() {
const editor = usePlateEditor({
components: {
blockquote: BlockquoteElement,
code: CodeLeaf,
},
plugins: [BlockquotePlugin, CodePlugin],
});
return (
The object keys are persisted element types or property keys, not plugin names, file names, or component names.
Use render.as when the default PlateElement or PlateLeaf wrapper is enough
and you only need a different HTML tag.
import { schema } from 'platejs';
import { definePlatePlugin } from 'platejs/react';
export const QuotePlugin = definePlatePlugin('quote', {
render: {
as: 'blockquote',
},
schema: {
element: { content: schema.content.text({ default: 'text', min: 1 }) },
},
});import { schema } from 'platejs';
import { definePlatePlugin } from 'platejs/react';
export const QuotePlugin = definePlatePlugin('quote', {
render: {
as: '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 plite-<node-type> class while
rendering plugin nodes, so global CSS can target stable node types when you need
editor-wide styling.
.plite-paragraph {
margin-block: 0.25rem;
}
.plite-code {
border-radius: 0.375rem;
font-family: var(--font-mono);
}.plite-paragraph {
margin-block: 0.25rem;
}
.plite-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 |
|---|---|---|
PlateElement | Element nodes. | Defaults to div; accepts as, className, style, and Plate render props. |
PlateLeaf | 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. |
render.as | Default wrapper with a different tag. | Works when no component is bound. |
components | Editor-wide component overrides. | Merged into the root plugin's component overrides. |
override.components | Advanced plugin-level component overrides. | Higher-priority plugins win when a target already has a component. |
For plugin method details, see Plugin Methods. For static rendering components, see Static Rendering.