Plate components connect a PlateEditor to React rendering. Use Plate and PlateContent for editable editors, PlateView for read-only static views, and the node primitives when writing custom plugin components.
Plate owns the editor store. PlateContent renders the editable surface under that store.
import { Plate, PlateContent, usePlateEditor } from "platejs/react";
export function Editor() {
const editor =
import { Plate, PlateContent, usePlateEditor } from "platejs/react";
export function Editor() {
const editor = usePlateEditor({
initialValue: [
{
children: [{ text: "Start writing." }],
type: "paragraph",
},
],
});
return (
<Plate editor={editor}>
<PlateContent placeholder="Write..." />
</Plate>
);
}PlateContent must render below Plate. useEditor() requires an active
editor and throws otherwise. Use useActiveEditor() only in controller UI
that intentionally handles null while no editor is active.
Use PlateView with a static editor when you need rendered content and Plate copy behavior without an editable surface.
import { PlateView, usePlateViewEditor } from "platejs/react";
const value = [
{
children: [{ text: "Published content." }],
type: "paragraph",
},
];
export function ReadOnlyEditor() {
const editor = usePlateViewEditor({ initialValue: value });
if (!editor) return null;
return <PlateView editor={editor} />;
}import { PlateView, usePlateViewEditor } from "platejs/react";
const value = [
{
children: [{ text: "Published content." }],
type: "paragraph",
},
];
export function ReadOnlyEditor() {
const editor = usePlateViewEditor({ initialValue: value });
if (!editor) return null;
return <PlateView editor={editor} />;
}PlateView wraps PlateStatic. Its default onCopy writes Plate fragment data to the clipboard, unless you pass your own onCopy prop.
| Component | Use For |
|---|---|
Plate | Store provider for one editor instance. |
PlateContent | Editable Plite surface with plugin on callbacks, decorators, renderers, hotkeys, and editor effects. |
PlateView | Static read-only rendering with Plate fragment copy support. |
PlateContainer | Editor container div plus beforeContainer and afterContainer plugin slots. |
NodeSelectionHighlight | Highlight overlays for selected selectable blocks. |
NodeSelectionDrag | Blank-space pointer-drag selection and its drag rectangle. |
Plite | Plite provider wrapper used by PlateContent; also applies abovePlite plugin wrappers. |
PlateElement | Default element renderer for block and inline elements. |
PlateLeaf | Default decorated text-leaf renderer. |
PlateText | Default text-node renderer for non-decoration leaf rendering. |
PlateTest | Test helper that creates or wraps an editor and renders PlateContent with test attributes. |
PlateContent composes editable props directly from store renderers, its own render props, plugin decorators, and plugin DOM events.
| Stage | Source |
|---|---|
| Plite provider | Plite receives the editor instance and store callbacks. |
| Editable props | PlateContent pipes decorators, DOM events, renderElement, renderLeaf, and renderText. |
| Plugin slots | beforeEditable, aboveEditable, and afterEditable wrap or sit around the editable surface. |
| Effects | EditorShortcutDispatcher, EditorRefEffect, and PlateControllerEffect run inside PlateContent. |
| Read-only state | disabled forces read-only; readOnly syncs back into the Plate store. |
Use PlateElement, PlateLeaf, and PlateText inside plugin components. They merge Plite attributes with your className, style, and ref.
import {
ParagraphPlugin,
PlateElement,
type PlateElementProps,
} from "platejs/react";
export function ParagraphElement(
props: PlateElementProps<typeof ParagraphPlugin>
) {
return <PlateElement as="p" className="leading-7" {...props} />;
}import {
ParagraphPlugin,
PlateElement,
type PlateElementProps,
} from "platejs/react";
export function ParagraphElement(
props: PlateElementProps<typeof ParagraphPlugin>
) {
return <PlateElement as="p" className="leading-7" {...props} />;
}Pass a plugin descriptor when the component belongs to one plugin. The props infer that plugin's configured element type.
import { QuotePlugin } from "@/components/editor/quote-plugin";
import { PlateElement, type PlateElementProps } from "platejs/react";
export function QuoteElement(props: PlateElementProps<typeof QuotePlugin>) {
return <PlateElement as="blockquote" {...props} />;
}import { QuotePlugin } from "@/components/editor/quote-plugin";
import { PlateElement, type PlateElementProps } from "platejs/react";
export function QuoteElement(props: PlateElementProps<typeof QuotePlugin>) {
return <PlateElement as="blockquote" {...props} />;
}Low-level renderer infrastructure that has no plugin owner uses the raw render contract instead:
import type { Element, RenderElementProps } from "platejs";
export function TypedElement<TElement extends Element>(
props: RenderElementProps<TElement>
) {
return <div {...props.attributes}>{props.children}</div>;
}import type { Element, RenderElementProps } from "platejs";
export function TypedElement<TElement extends Element>(
props: RenderElementProps<TElement>
) {
return <div {...props.attributes}>{props.children}</div>;
}When a schema element owns a named content root, render it through the typed
slots.contentRoot(slot) function. The same component works in interactive and
static rendering; Plate chooses an editable root view or static root children.
import { FigurePlugin } from "@/components/editor/figure-plugin";
import type { PlateElementProps } from "platejs/react";
export function FigureElement({
attributes,
children,
slots,
}: PlateElementProps<typeof FigurePlugin>) {
return (
<figure {...attributes}>
{children}
<figcaption>{slots.contentRoot("caption")}</figcaption>
</figure>
);
}import { FigurePlugin } from "@/components/editor/figure-plugin";
import type { PlateElementProps } from "platejs/react";
export function FigureElement({
attributes,
children,
slots,
}: PlateElementProps<typeof FigurePlugin>) {
return (
<figure {...attributes}>
{children}
<figcaption>{slots.contentRoot("caption")}</figcaption>
</figure>
);
}| Primitive | Behavior |
|---|---|
PlateElement | Adds data-plite-node="element", preserves Plite's data-plite-node-key, exposes typed element-owned content-root slots, and adds directional-affinity spacers when needed. |
PlateLeaf | Renders a text leaf and adds hard-affinity spacers when needed. |
PlateText | Renders a text node without leaf-decoration matching. |
Plite stores node selection in the editor model. Plate React provides two
independent DOM primitives for its visual presentation and pointer-drag input.
Compose them as siblings after PlateContent under the same Plate provider.
import {
NodeSelectionDrag,
NodeSelectionHighlight,
PlateContent,
type PlateContentProps,
} from "platejs/react";
export function Editor(props: PlateContentProps) {
return (
<>
<PlateContent {...props} />
<NodeSelectionHighlight className="z-1 bg-brand/[.13]" />
<NodeSelectionDrag className="z-50 border border-brand/25 bg-brand/15" />
</>
);
}import {
NodeSelectionDrag,
NodeSelectionHighlight,
PlateContent,
type PlateContentProps,
} from "platejs/react";
export function Editor(props: PlateContentProps) {
return (
<>
<PlateContent {...props} />
<NodeSelectionHighlight className="z-1 bg-brand/[.13]" />
<NodeSelectionDrag className="z-50 border border-brand/25 bg-brand/15" />
</>
);
}NodeSelectionHighlight portals a highlight into each selected block.
NodeSelectionDrag renders the active drag rectangle in document.body and
writes intersecting blocks through the editor's selection API. Selection
candidates must pass editor.read.schema.isBlockContent(element) and
editor.read.nodes.isSelectable(element).
Structural internals opt out with blockContent: false. A block that owns
custom highlight geometry sets data-node-selection-highlight="self" and can
read its exact state with useElementSelected({ mode: "node" }).
| Primitive | DOM contract |
|---|---|
NodeSelectionHighlight | Accepts div attributes except children; renders data-slot="node-selection-highlight" with required inset positioning. |
NodeSelectionDrag | Accepts div attributes except children; renders data-slot="node-selection-drag" with required fixed positioning. |
Use the Selection API for model reads and writes. See the Node Selection demo for the copied Editor composition.
Root provider for one editor instance.
Editor instance. When null, Plate renders nothing.
React children that can read the Plate store.
Store-level decorate function used by PlateContent.
Store-level read-only state. Defaults to editor.dom.readOnly.
Registers the editor as a primary editor for PlateController.
Fallback element renderer stored on the Plate store.
Fallback leaf renderer stored on the Plate store.
Observes every published editor commit for the lifetime of the Plate
provider.
Observes commits that change the serializable document. value contains
primary children, named roots, and persisted meta.
Observes commits that change the primary-root selection.
Observes canonical node changes for the lifetime of the Plate provider.
Observes canonical text changes for the lifetime of the Plate provider.
Suppresses the multiple-instance warning from usePlateInstancesWarn.
Editable surface for a Plate editor.
Editor scope used by useEditor({id}) and usePlateStore(id).
Focuses the editor at the end when readOnly changes from true to
false.
Forces read-only state and sets aria-disabled.
Overrides the store read-only value and syncs it back to the store.
Editable-level decorate function. Store-level decorate wins when
present.
Wraps or replaces the generated Editable element.
Fallback element renderer after plugin renderers.
Fallback leaf renderer after plugin leaf renderers.
Fallback text renderer after non-decoration text renderers.
Placeholder renderer passed to Plite Editable.
Placeholder text passed to Plite Editable.
Plite selection scrolling hook.
DOM before-input handler passed through the plugin handler pipeline.
Keyboard handler passed through the plugin handler pipeline.
Element type passed to Plite Editable.
Passed to Plite Editable.
ARIA role passed to Plite Editable.
Style object passed to Plite Editable.
PlateContent also accepts the DOM handler props listed in DOMHandlers, including clipboard, composition, focus, keyboard, pointer, mouse, drag, touch, media, and form handlers.
Read-only static renderer with Plate copy support.
Container div with plugin container slots.
| API | Default Element | Notes |
|---|---|---|
PlateElement | div | Accepts as, attributes, className, style, ref, element, path, editor, plugin, and insetProp. |
PlateLeaf | span | Accepts as, attributes, className, style, ref, leaf, text, editor, plugin, and inset. |
PlateText | span | Accepts as, attributes, className, style, ref, text, editor, and plugin. |