From zbeyens. The source code is available on GitHub.

Plate
PlatePliteEditorsTemplates
GitHub16kGitHub
DiscordDiscord
  • Feature Kits
  • Plugin
    • Plugin Methods
    • Plugin Shortcuts
    • Plugin Context
    • Plugin Components
    • Plugin Rules
    • Editing Behavior
    • Plugin Input Rules
  • Editor
    • Editor Methods
    • Controlled Value
  • Performance
  • Static Rendering
  • HTML
  • Markdown
  • Form
  • TypeScript
  • Debugging
  • Unit Testing
  • Browser
  • Troubleshooting

Plugin Components

PreviousNext

Render Plate plugin nodes with React components.

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.

Start with Plate UI

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 hereUse when
Plate UIYou want registry components copied into your app.
Plugin ContextPlugin Rules

On This Page

Start with Plate UIComponent PrimitivesPlateElementPlateLeafRegister ComponentsExisting PluginComponent With Consumer OverridesEditor componentsRender Without a Custom ComponentStylingAPI Reference
Build your editor
Production-ready AI template and reusable components.
Get all-access
Feature Kits
You want plugin groups that already wire components, shortcuts, and options.
This pageYou are writing or replacing a component by hand.

The package owns plugin behavior. Your app owns copied component files and their styles.

Component Primitives

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.

Render children

Always render children. Plite needs the children in the DOM even when the element is void or the visible UI comes from surrounding controls.

PlateElement

Element components render block, inline, and void element nodes.

components/editor/blockquote.tsx
'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>
  );
}
components/editor/blockquote.tsx
'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.

PlateLeaf

Leaf components render marked and decorated text ranges.

components/editor/code.tsx
'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>
  );
}
components/editor/code.tsx
'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.

Register Components

Declare component in a new Plate plugin, or include it in the existing descriptor's single terminal .configure() call.

Existing Plugin

Use .configure({ component }) to attach a React component to a plugin.

components/editor/plugins.tsx
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 }),
];
components/editor/plugins.tsx
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 }),
];

Component With Consumer Overrides

When the same plugin also needs rules, shortcuts, initial state, or input rules, put every override in that same terminal .configure() call.

components/editor/plugins.tsx
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' } },
  }),
];
components/editor/plugins.tsx
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' } },
  }),
];

Editor components

Use the editor components option when a single editor owns the component map. This is useful for replacing several components in one place.

components/editor.tsx
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>
  );
}
components/editor.tsx
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.

Render Without a Custom Component

Use render.as when the default PlateElement or PlateLeaf wrapper is enough and you only need a different HTML tag.

quote-plugin.ts
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 }) },
  },
});
quote-plugin.ts
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.

Styling

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.

app/globals.css
.plite-paragraph {
  margin-block: 0.25rem;
}
 
.plite-code {
  border-radius: 0.375rem;
  font-family: var(--font-mono);
}
app/globals.css
.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 Reference

APIUse forNotes
PlateElementElement nodes.Defaults to div; accepts as, className, style, and Plate render props.
PlateLeafMarked 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.asDefault wrapper with a different tag.Works when no component is bound.
componentsEditor-wide component overrides.Merged into the root plugin's component overrides.
override.componentsAdvanced 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.

<Plate editor={editor}>
<EditorContainer>
<Editor />
</EditorContainer>
</Plate>
);
}