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:
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
Configuration options including display settings and shortcuts
Methods for manipulating plugin content programmatically
Event handlers for keyboard, mouse, and other DOM events
Hooks that run at specific points in the plugin lifecycle
Serialization and deserialization for HTML, Markdown, and Email
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
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
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
React component that renders the element
Default props for the element
nodeType
'block' | 'void' | 'inline'
Type of Slate node. Default is ‘block’
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 configuration - title - Display name in UI - description - Plugin description - icon
Keyboard shortcuts to trigger the plugin
Slate-specific configuration
Plugin Loading Order
The order of plugins in the array affects:
Menu display order
Transform priority
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
Always include Paragraph plugin
The Paragraph plugin should always be included as it’s the default block type.
Define plugins outside component
Define your plugins array outside the component to prevent recreation on every render.
Use extend() for customization
Use the extend() method instead of modifying plugin objects directly.
Handle async operations properly
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