Skip to main content

Rich text editor
plugin system for
Slate & React

Rapidly build your rich-text editor with Slate

Declarative & Familiar

Plate takes care of the repetitive and annoying stuff so you don't have to. This means you spend less time wiring up your editor features and more time focusing on your business logic with minimal slate knowledge.

Pluggable & Functional

A plugin system allows you to easily enable additional functionality, and package your own plugins in a common format. Tons of queries and transforms are provided to create your own plugins, and confidently implement complex behavior.

Plate Cloud: Image and Attachment uploads

New! Plate introduces its official cloud image and attachment upload service with image resizing. Quickly add upload support to any Plate editor and support your favorite editor.

Less Code. Fewer Edge Cases.

Plate comes with battle-tested solutions for formatting, events handlers, rendering, serializing, normalizing, you literally write a tiny fraction of the code you normally would. This means you spend less time writing code and more time building your next big thing.

import React, { CSSProperties, useMemo, useRef } from 'react';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import {
  AutoformatPlugin,
  createAlignPlugin,
  createAutoformatPlugin,
  createBlockquotePlugin,
  createBoldPlugin,
  createCodeBlockPlugin,
  createCodePlugin,
  createComboboxPlugin,
  createDeserializeCsvPlugin,
  createDeserializeDocxPlugin,
  createDeserializeMdPlugin,
  createDndPlugin,
  createExitBreakPlugin,
  createFontBackgroundColorPlugin,
  createFontColorPlugin,
  createFontSizePlugin,
  createHeadingPlugin,
  createHighlightPlugin,
  createHorizontalRulePlugin,
  createImagePlugin,
  createIndentPlugin,
  createItalicPlugin,
  createKbdPlugin,
  createLinkPlugin,
  createListPlugin,
  createMediaEmbedPlugin,
  createMentionPlugin,
  createNodeIdPlugin,
  createNormalizeTypesPlugin,
  createParagraphPlugin,
  createPlateUI,
  createResetNodePlugin,
  createSelectOnBackspacePlugin,
  createSoftBreakPlugin,
  createStrikethroughPlugin,
  createSubscriptPlugin,
  createSuperscriptPlugin,
  createTablePlugin,
  createTodoListPlugin,
  createTrailingBlockPlugin,
  createUnderlinePlugin,
  MentionCombobox,
  Plate,
  PlateProvider,
} from '@udecode/plate';
import { createJuicePlugin } from '@udecode/plate-juice';
import { createBlockSelectionPlugin } from '@udecode/plate-selection';
import {
  createExcalidrawPlugin,
  ELEMENT_EXCALIDRAW,
  ExcalidrawElement,
} from '@udecode/plate-ui-excalidraw';
import { alignPlugin } from './align/alignPlugin';
import { autoformatPlugin } from './autoformat/autoformatPlugin';
import { MarkBalloonToolbar } from './balloon-toolbar/MarkBalloonToolbar';
import { editableProps } from './common/editableProps';
import { CursorOverlayContainer } from './cursor-overlay/CursorOverlayContainer';
import { dragOverCursorPlugin } from './cursor-overlay/dragOverCursorPlugin';
import { withStyledDraggables } from './dnd/withStyledDraggables';
import { exitBreakPlugin } from './exit-break/exitBreakPlugin';
import { forcedLayoutPlugin } from './forced-layout/forcedLayoutPlugin';
import { indentPlugin } from './indent/indentPlugin';
import { linkPlugin } from './link/linkPlugin';
import { MENTIONABLES } from './mention/mentionables';
import { withStyledPlaceHolders } from './placeholder/withStyledPlaceHolders';
import { resetBlockTypePlugin } from './reset-node/resetBlockTypePlugin';
import { selectOnBackspacePlugin } from './select-on-backspace/selectOnBackspacePlugin';
import { softBreakPlugin } from './soft-break/softBreakPlugin';
import { Toolbar } from './toolbar/Toolbar';
import { trailingBlockPlugin } from './trailing-block/trailingBlockPlugin';
import {
  createMyPlugins,
  MyEditor,
  MyPlatePlugin,
  MyValue,
} from './typescript/plateTypes';
import { playgroundValue } from './playgroundValue';
import { ToolbarButtons } from './ToolbarButtons';

let components = createPlateUI({
  [ELEMENT_EXCALIDRAW]: ExcalidrawElement,
  // customize your components by plugin key
});
components = withStyledPlaceHolders(components);

const styles: Record<string, CSSProperties> = {
  container: { position: 'relative' },
};

const App = () => {
  const containerRef = useRef(null);

  const plugins = useMemo(
    () =>
      createMyPlugins(
        [
          createParagraphPlugin(),
          createBlockquotePlugin(),
          createTodoListPlugin(),
          createHeadingPlugin(),
          createImagePlugin(),
          createHorizontalRulePlugin(),
          createLinkPlugin(linkPlugin),
          createListPlugin(),
          createTablePlugin(),
          createMediaEmbedPlugin(),
          createExcalidrawPlugin() as MyPlatePlugin,
          createCodeBlockPlugin(),
          createAlignPlugin(alignPlugin),
          createBoldPlugin(),
          createCodePlugin(),
          createItalicPlugin(),
          createHighlightPlugin(),
          createUnderlinePlugin(),
          createStrikethroughPlugin(),
          createSubscriptPlugin(),
          createSuperscriptPlugin(),
          createFontColorPlugin(),
          createFontBackgroundColorPlugin(),
          createFontSizePlugin(),
          createKbdPlugin(),
          createNodeIdPlugin(),
          createBlockSelectionPlugin(),
          createDndPlugin({ options: { enableScroller: true } }),
          dragOverCursorPlugin,
          createIndentPlugin(indentPlugin),
          createAutoformatPlugin<
            AutoformatPlugin<MyValue, MyEditor>,
            MyValue,
            MyEditor
          >(autoformatPlugin),
          createResetNodePlugin(resetBlockTypePlugin),
          createSoftBreakPlugin(softBreakPlugin),
          createExitBreakPlugin(exitBreakPlugin),
          createNormalizeTypesPlugin(forcedLayoutPlugin),
          createTrailingBlockPlugin(trailingBlockPlugin),
          createSelectOnBackspacePlugin(selectOnBackspacePlugin),
          createComboboxPlugin(),
          createMentionPlugin(),
          createDeserializeMdPlugin(),
          createDeserializeCsvPlugin(),
          createDeserializeDocxPlugin(),
          createJuicePlugin() as MyPlatePlugin,
        ],
        {
          components: withStyledDraggables(components),
        }
      ),
    []
  );

  return (
    <DndProvider backend={HTML5Backend}>
      <PlateProvider<MyValue> initialValue={playgroundValue} plugins={plugins}>
        <Toolbar>
          <ToolbarButtons />
        </Toolbar>

        <div ref={containerRef} style={styles.container}>
          <Plate editableProps={editableProps}>
            <MarkBalloonToolbar />

            <MentionCombobox items={MENTIONABLES} />

            <CursorOverlayContainer containerRef={containerRef} />
          </Plate>
        </div>
      </PlateProvider>
    </DndProvider>
  );
};

export default App;

One Dep, All the Features.

Plate is strategically packed with features you're bound to need in almost any editor, tidying up the elements, marks, serializers, normalizers, queries, transforms, components, and many complex behaviors.

40+ PackagesDesign SystemContext-lessState ManagementAutomatic Garbage CollectionMultiple EditorsEditor PluginsElementsMarksQueriesTransformsNormalizersSerializersTree shakeableTypeScript Types