Skip to main content

Overview

Plugins are the building blocks of Yoopta Editor. Each plugin represents a specific type of content block (paragraph, heading, image, etc.) and defines how that content is rendered and behaves. Every plugin in Yoopta Editor is built using the YooptaPlugin class, which provides a consistent API for defining block types, handling events, managing state, and extending functionality.

Plugin Architecture

YooptaPlugin Class

All plugins are created using the YooptaPlugin class constructor:
import { YooptaPlugin } from '@yoopta/editor';

const MyPlugin = new YooptaPlugin({
  type: 'MyPlugin',
  elements: {
    // Plugin elements definition
  },
  options: {
    // Plugin options
  },
  commands: {
    // Plugin commands
  },
  events: {
    // Event handlers
  },
  lifecycle: {
    // Lifecycle hooks
  },
  parsers: {
    // HTML, Markdown, Email parsers
  },
  extensions: {
    // Slate extensions
  },
});

Plugin Structure

Each plugin configuration consists of:
type
string
required
Unique identifier for the plugin (e.g., ‘Paragraph’, ‘Image’, ‘Code’)
elements
object | JSX.Element
required
Defines the structure and rendering of plugin elements. Can be an object or JSX syntax
options
object
Configuration options including display settings and shortcuts
commands
object
Methods for manipulating plugin content programmatically
events
object
Event handlers for keyboard, mouse, and other DOM events
lifecycle
object
Hooks that run at specific points in the plugin lifecycle
parsers
object
Serialization and deserialization for HTML, Markdown, and Email
extensions
function
Slate editor extensions for custom behavior

Available Plugins

Yoopta Editor provides a rich set of built-in plugins:

Text Plugins

  • Paragraph - Basic text blocks
  • Headings - H1, H2, H3 heading blocks
  • Blockquote - Quote blocks

List Plugins

  • BulletedList - Unordered lists
  • NumberedList - Ordered lists
  • TodoList - Checkable task lists

Media Plugins

  • Image - Image blocks with upload support
  • Video - Video blocks with upload support
  • File - File attachment blocks
  • Embed - Embed external content (YouTube, Twitter, etc.)

Layout Plugins

  • Table - Tabular data
  • Tabs - Tabbed content sections
  • Steps - Step-by-step instructions
  • Carousel - Image/content carousel
  • Accordion - Collapsible content sections
  • Divider - Horizontal separator
  • Callout - Highlighted notice blocks

Code Plugins

  • Code - Syntax-highlighted code blocks
  • CodeGroup - Tabbed code blocks with multiple files

Special Plugins

  • Link - Link blocks

Using Plugins

Basic Usage

import Paragraph from '@yoopta/paragraph';
import Blockquote from '@yoopta/blockquote';
import Code from '@yoopta/code';

const plugins = [Paragraph, Blockquote, Code];

<YooptaEditor
  editor={editor}
  plugins={plugins}
  // ... other props
/>;

Headings Plugin

The Headings plugin exports multiple heading types:
import Headings from '@yoopta/headings';

const plugins = [
  Headings.HeadingOne, // H1
  Headings.HeadingTwo, // H2
  Headings.HeadingThree, // H3
];

Lists Plugin

The Lists plugin exports multiple list types:
import Lists from '@yoopta/lists';

const plugins = [Lists.BulletedList, Lists.NumberedList, Lists.TodoList];

Plugin Configuration

Most plugins accept configuration options:

Image Plugin

import Image from '@yoopta/image';

const plugins = [
  Image.extend({
    options: {
      async onUpload(file) {
        // Custom upload logic
        const url = await uploadToServer(file);
        return { src: url };
      },
      maxWidth: 1000,
      minWidth: 100,
    },
  }),
];

Code Plugin

import Code from '@yoopta/code';

const plugins = [
  Code.extend({
    options: {
      theme: 'github-dark',
      language: 'javascript',
      languages: ['javascript', 'typescript', 'python', 'rust'],
    },
  }),
];

Video Plugin

import Video from '@yoopta/video';

const plugins = [
  Video.extend({
    options: {
      async onUpload(file) {
        const url = await uploadVideo(file);
        return { src: url, provider: 'custom' };
      },
      maxSize: 100 * 1024 * 1024, // 100MB
      accept: 'video/*',
    },
  }),
];

Plugin Methods

extend()

Extend a plugin with custom options:
const CustomParagraph = Paragraph.extend({
  options: {
    // Custom options
  },
  renders: {
    // Custom renderers
  },
});

Defining Elements

Elements can be defined in two ways: 1. Object Syntax:
const MyPlugin = new YooptaPlugin({
  type: 'MyPlugin',
  elements: {
    'my-element': {
      render: (props) => <div {...props.attributes}>{props.children}</div>,
      props: {
        /* default props */
      },
      nodeType: 'block', // or 'void' or 'inline'
    },
  },
});
2. JSX Syntax (Recommended):
const MyPlugin = new YooptaPlugin({
  type: 'MyPlugin',
  elements: (
    <my-container render={MyContainer}>
      <my-item render={MyItem} />
    </my-container>
  ),
});

Element Properties

render
function
required
React component that renders the element
props
object
Default props for the element
nodeType
'block' | 'void' | 'inline'
Type of Slate node. Default is ‘block’
placeholder
string
Placeholder text for empty elements

Custom Renders

Override default rendering:
import Paragraph from '@yoopta/paragraph';

const CustomParagraph = Paragraph.extend({
  renders: {
    paragraph: (props) => {
      return (
        <p className="custom-paragraph" {...props.attributes}>
          {props.children}
        </p>
      );
    },
  },
});

Plugin Events

Handle plugin-specific events:
const CustomImage = Image.extend({
  events: {
    onPaste: (editor, slate, options) => {
      return (event) => {
        console.log('onPaste', event);
      };
    },
    onKeyDown: (editor, slate, options) => {
      return (event) => {
        console.log('onKeyDown', event);
      };
    },
  },
});

Plugin Shortcuts

Define custom keyboard shortcuts:
const CustomCode = Code.extend({
  shortcuts: {
    'mod+shift+c': (editor) => {
      // Transform current block to code block
      editor.blocks.toggle({ type: 'Code' });
    },
  },
});

Common Plugin Options

Most plugins support these common options:
display
object
Display configuration - title - Display name in UI - description - Plugin description - icon
  • Custom icon component
shortcuts
string[]
Keyboard shortcuts to trigger the plugin
slate
object
Slate-specific configuration

Plugin Loading Order

The order of plugins in the array affects:
  1. Menu display order
  2. Transform priority
  3. Shortcut precedence
const plugins = [
  Paragraph, // Shows first in menus
  Headings.HeadingOne,
  Headings.HeadingTwo,
  // ...
  Divider, // Shows last in menus
];

Conditional Plugin Loading

Load plugins based on conditions:
const plugins = [
  Paragraph,
  Headings.HeadingOne,
  // Conditionally include plugins
  ...(enableMedia ? [Image, Video] : []),
  ...(enableCode ? [Code] : []),
];

Plugin Detection

Check if a plugin is loaded:
const hasImagePlugin = plugins.some((p) => p.type === 'Image');

Best Practices

The Paragraph plugin should always be included as it’s the default block type.
Define your plugins array outside the component to prevent recreation on every render.
Use the extend() method instead of modifying plugin objects directly.
For plugins with async operations (uploads, etc.), always handle errors and loading states.

Lifecycle Hooks

Lifecycle hooks allow you to run code at specific points in a block’s lifecycle:
const MyPlugin = new YooptaPlugin({
  type: 'MyPlugin',
  lifecycle: {
    beforeCreate: (editor) => {
      // Return initial block structure
      return editor.y('my-element', {
        children: [editor.y.text('Initial content')],
      });
    },
    onCreate: (editor, block) => {
      // Run after block is created
    },
    onDestroy: (editor, block) => {
      // Cleanup before block is destroyed
    },
  },
});

Available Lifecycle Hooks

beforeCreate
(editor: YooEditor) => SlateElement
Called before a block is created. Return the initial structure
onCreate
(editor: YooEditor, block: YooptaBlockData) => void
Called after a block is created
onDestroy
(editor: YooEditor, block: YooptaBlockData) => void
Called before a block is destroyed

Parsers

Parsers handle serialization and deserialization of content:
const MyPlugin = new YooptaPlugin({
  type: 'MyPlugin',
  parsers: {
    html: {
      deserialize: {
        nodeNames: ['DIV'],
        parse: (el) => {
          // Convert HTML element to Slate node
          return {
            type: 'my-element',
            children: [{ text: el.textContent }],
          };
        },
      },
      serialize: (element, text, blockMeta) => {
        // Convert Slate node to HTML string
        return `<div>${text}</div>`;
      },
    },
    markdown: {
      serialize: (element, text) => {
        // Convert to Markdown
        return `${text}\n`;
      },
    },
    email: {
      serialize: (element, text) => {
        // Convert to email-compatible HTML
        return `<table><tr><td>${text}</td></tr></table>`;
      },
    },
  },
});

Next Steps