Plugin Components

Learn how to create and style custom components for Plate plugins.

By default, Plate plugins are headless, meaning all nodes will be rendered as plain text. This guide will show you how to create and style custom components for your editor.

Plate UI

Unless you prefer to build everything from scratch, we recommend using Plate UI to get started. Plate UI is a collection of components that you can copy into your app and modify to suit your needs.

The process of creating and registering components is similar whether you use Plate UI or build your own from scratch.

Defining Components

Use PlateElement for element nodes (like paragraphs, headings) and PlateLeaf for text leaf nodes (like bold, italic). These components handle applying the necessary Plate props to your custom HTML elements.

Ensure the children prop is rendered unconditionally for the editor to function correctly, even for void nodes.

Element Component

import { type PlateElementProps, PlateElement } from 'platejs/react';
 
export function BlockquoteElement(props: PlateElementProps) {
  // props contains attributes, children, element, editor, etc.
  // plus any custom props your plugin might pass.
  return (
    <PlateElement
      as="blockquote"
      className="my-1 border-l-2 pl-6 italic" // Apply custom styles directly
      {...props} // Pass all original props (attributes, children, element, etc.)
    />
  );
}

This example defines a BlockquoteElement. The as prop on PlateElement specifies that it should render an HTML <blockquote>. PlateElement handles rendering the children passed via {...props}.

Leaf Component

import { type PlateLeafProps, PlateLeaf } from 'platejs/react';
 
export function CodeLeaf(props: PlateLeafProps) {
  // props contains attributes, children, leaf, text, editor, etc.
  // plus any custom props your plugin might pass.
  return (
    <PlateLeaf
      as="code"
      className="rounded-md bg-muted px-[0.3em] py-[0.2em] font-mono text-sm" // Apply custom styles
      {...props} // Pass all original props (attributes, children, leaf, text, etc.)
    />
  );
}

Styling

We recommend styling components using Tailwind CSS, as demonstrated in Plate UI.

Alternatively, Plate generates class names like slate-<node-type> (e.g., slate-p for paragraphs, slate-h1 for H1 headings) which you can target with global CSS:

.slate-p {
  margin-bottom: 1rem;
}
.slate-bold {
  font-weight: bold;
}

Register Components

To use your custom components, register them with the corresponding plugin or directly in the editor configuration.

The withComponent method is the most straightforward way to associate a component with a plugin.

const plugins = [
  // This is equivalent to:
  // ParagraphPlugin.configure({ node: { component: MyParagraphElement }});
  ParagraphPlugin.withComponent(MyParagraphElement),
  CodeBlockPlugin.withComponent(MyCodeBlockElement),
  CodeLinePlugin.withComponent(MyCodeLineElement),
  CodeSyntaxPlugin.withComponent(MyCodeSyntaxLeaf),
]

Method 2: Plugin override.components

For plugins that manage multiple component parts (like CodeBlockPlugin with code_block, code_line, and code_syntax), or when you need to override components for a specific plugin instance, use the override.components option within configure.

const plugins = [
  CodeBlockPlugin.configure({
    override: {
      components: {
        [CodeBlockPlugin.key]: MyCodeBlockElement,
        [CodeLinePlugin.key]: MyCodeLineElement,
        [CodeSyntaxPlugin.key]: MyCodeSyntaxLeaf,
      },
    },
  }),
];

Method 3: Editor components Option

You can globally map plugin keys to components in createPlateEditor (or usePlateEditor). This is useful for managing all components in one place, or for plugins composed of multiple plugins.

const editor = createPlateEditor({
  plugins: [ParagraphPlugin, CodeBlockPlugin /* ...other plugins */],
  components: {
    [ParagraphPlugin.key]: MyParagraphElement,
    [CodeBlockPlugin.key]: MyCodeBlockElement,
    [CodeLinePlugin.key]: MyCodeLineElement,
    [CodeSyntaxPlugin.key]: MyCodeSyntaxLeaf,
    // ...other component overrides
  },
});