How to Integrate Yoopta Editor into Your Next.js or React Application
Introduction
Sample Repo - https://github.com/SH20RAJ/yoopta-editor-example/tree/74df92fbbb7a9b2c2fb01eabda5f7ff9befcebe4
Rich text editors are an essential part of modern web applications, allowing users to create and edit content with formatted text, images, videos, and other interactive elements. In this tutorial, I'll walk you through integrating the powerful Yoopta editor into your Next.js or React application.
Yoopta is a flexible, customizable rich text editor that provides a variety of plugins for different content types. It's built on the Slate.js framework and offers a great developer experience with its modular architecture.
Prerequisites
- Basic knowledge of React or Next.js
- Node.js and npm installed on your machine
- An existing React or Next.js project
Step 1: Install Core Dependencies
First, let's install the core Yoopta dependencies:
# For React applications
npm install --save --legacy-peer-deps @yoopta/editor slate slate-react
# For Next.js applications with App Router
npm install --save --legacy-peer-deps @yoopta/editor slate@0.102.0 slate-react@0.102.0
Note: For Next.js applications, especially those using the App Router, it's important to use specific versions of slate (0.102.0) and slate-react (0.102.0) to avoid compatibility issues.
Step 2: Install Yoopta Plugins
Yoopta's strength lies in its plugin system. Here's how to install the most commonly used plugins:
npm install --save --legacy-peer-deps \
@yoopta/paragraph \
@yoopta/headings \
@yoopta/blockquote \
@yoopta/lists \
@yoopta/image \
@yoopta/link \
@yoopta/table \
@yoopta/code \
@yoopta/marks \
@yoopta/divider \
@yoopta/toolbar \
@yoopta/action-menu-list
Each plugin adds specific functionality to your editor:
-
paragraph
: Basic paragraph formatting -
headings
: Multiple heading levels -
blockquote
: Quote formatting -
lists
: Ordered, unordered, and todo lists -
image
: Image uploads and display -
link
: Hyperlink creation and editing -
table
: Table creation and editing -
code
: Code block formatting -
marks
: Text formatting (bold, italic, etc.) -
divider
: Horizontal dividers -
toolbar
: Floating formatting toolbar -
action-menu-list
: Action menu for inserting content blocks
Step 3: Create the Basic Editor Component
For a Next.js application using the App Router, make sure to add the 'use client'
directive at the top of your component file.
Here's a minimal setup for Yoopta Editor:
'use client'; // Only needed for Next.js App Router
import YooptaEditor, { createYooptaEditor } from '@yoopta/editor';
import { useMemo } from 'react';
// Import plugins
import Paragraph from '@yoopta/paragraph';
function SimpleEditor() {
// Create the editor instance
const editor = useMemo(() => createYooptaEditor(), []);
return (
<div className="editor-container">
<YooptaEditor
editor={editor}
plugins={[Paragraph]}
defaultValue={[
{
type: 'paragraph',
children: [{ text: 'Start typing here...' }],
},
]}
/>
</div>
);
}
export default SimpleEditor;
Step 4: Configure Multiple Plugins
Let's enhance our editor with more plugins:
import YooptaEditor, { createYooptaEditor } from '@yoopta/editor';
import { useMemo, useState } from 'react';
// Import plugins
import Paragraph from '@yoopta/paragraph';
import { HeadingOne, HeadingTwo, HeadingThree } from '@yoopta/headings';
import Blockquote from '@yoopta/blockquote';
import { NumberedList, BulletedList, TodoList } from '@yoopta/lists';
import { Bold, Italic, Underline, Strike, Highlight } from '@yoopta/marks';
import Table from '@yoopta/table';
import Code from '@yoopta/code';
import Divider from '@yoopta/divider';
import Link from '@yoopta/link';
// Define the plugins array
const plugins = [
Paragraph,
HeadingOne,
HeadingTwo,
HeadingThree,
Blockquote,
NumberedList,
BulletedList,
TodoList,
Code,
Table,
Link,
Divider,
];
// Define the text formatting marks
const MARKS = [Bold, Italic, Underline, Strike, Highlight];
function EnhancedEditor() {
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'Start writing with Yoopta Editor!' }],
},
]);
const editor = useMemo(() => createYooptaEditor(), []);
const onChange = (newValue) => {
setValue(newValue);
};
return (
<div className="editor-container">
<YooptaEditor
editor={editor}
plugins={plugins}
marks={MARKS}
value={value}
onChange={onChange}
autoFocus
/>
</div>
);
}
export default EnhancedEditor;
Step 5: Add Toolbar and Action Menu
To allow users to easily format text and insert content blocks, let's add the toolbar and action menu:
import ActionMenuList, { DefaultActionMenuRender } from '@yoopta/action-menu-list';
import Toolbar, { DefaultToolbarRender } from '@yoopta/toolbar';
import LinkTool, { DefaultLinkToolRender } from '@yoopta/link-tool';
// Define tools configuration
const TOOLS = {
ActionMenu: {
render: DefaultActionMenuRender,
tool: ActionMenuList,
},
Toolbar: {
render: DefaultToolbarRender,
tool: Toolbar,
},
LinkTool: {
render: DefaultLinkToolRender,
tool: LinkTool,
},
};
function EditorWithTools() {
// ...existing code...
return (
<div className="editor-container" ref={containerRef}>
<YooptaEditor
editor={editor}
plugins={plugins}
tools={TOOLS}
marks={MARKS}
selectionBoxRoot={containerRef}
value={value}
onChange={onChange}
autoFocus
/>
</div>
);
}
Step 6: Add Image and File Upload Support
To handle file uploads, you'll need to extend the image and file plugins with upload handlers:
import Image from '@yoopta/image';
import Video from '@yoopta/video';
import File from '@yoopta/file';
// Define plugins with upload capabilities
const plugins = [
// ...other plugins,
Image.extend({
options: {
async onUpload(file) {
// Replace with your actual upload logic
const data = await uploadToServer(file, 'image');
return {
src: data.url,
alt: 'Image description',
sizes: {
width: data.width,
height: data.height,
},
};
},
},
}),
Video.extend({
options: {
onUpload: async (file) => {
const data = await uploadToServer(file, 'video');
return {
src: data.url,
alt: 'Video description',
sizes: {
width: data.width,
height: data.height,
},
};
},
onUploadPoster: async (file) => {
const image = await uploadToServer(file, 'image');
return image.url;
},
},
}),
File.extend({
options: {
onUpload: async (file) => {
const response = await uploadToServer(file, 'file');
return {
src: response.url,
format: response.format,
name: response.name,
size: response.size
};
},
},
}),
];
// Example upload function using FormData
async function uploadToServer(file, resourceType) {
const formData = new FormData();
formData.append('file', file);
formData.append('resource_type', resourceType);
const response = await fetch('/api/upload', {
method: 'POST',
body: formData,
});
if (!response.ok) {
throw new Error('Upload failed');
}
return response.json();
}
Step 7: Create a Complete Editor Setup
Let's put everything together to create a complete Yoopta Editor implementation:
'use client';
import YooptaEditor, { createYooptaEditor } from '@yoopta/editor';
import { useMemo, useRef, useState } from 'react';
// Import all plugins
import Paragraph from '@yoopta/paragraph';
import { HeadingOne, HeadingTwo, HeadingThree } from '@yoopta/headings';
import Blockquote from '@yoopta/blockquote';
import { NumberedList, BulletedList, TodoList } from '@yoopta/lists';
import { Bold, Italic, CodeMark, Underline, Strike, Highlight } from '@yoopta/marks';
import Table from '@yoopta/table';
import Code from '@yoopta/code';
import Divider from '@yoopta/divider';
import Link from '@yoopta/link';
import Image from '@yoopta/image';
import Video from '@yoopta/video';
import File from '@yoopta/file';
import ActionMenuList, { DefaultActionMenuRender } from '@yoopta/action-menu-list';
import Toolbar, { DefaultToolbarRender } from '@yoopta/toolbar';
import LinkTool, { DefaultLinkToolRender } from '@yoopta/link-tool';
// Define plugins
const plugins = [
Paragraph,
Table,
Divider,
HeadingOne,
HeadingTwo,
HeadingThree,
Blockquote,
NumberedList,
BulletedList,
TodoList,
Code,
Link,
Image.extend({
options: {
async onUpload(file) {
// Your upload implementation
const data = await uploadToServer(file, 'image');
return {
src: data.url,
alt: 'Uploaded image',
sizes: {
width: data.width,
height: data.height,
},
};
},
},
}),
Video.extend({
options: {
// Video upload implementation
},
}),
File.extend({
options: {
// File upload implementation
},
}),
];
// Define tools
const TOOLS = {
ActionMenu: {
render: DefaultActionMenuRender,
tool: ActionMenuList,
},
Toolbar: {
render: DefaultToolbarRender,
tool: Toolbar,
},
LinkTool: {
render: DefaultLinkToolRender,
tool: LinkTool,
},
};
// Define text marks
const MARKS = [Bold, Italic, CodeMark, Underline, Strike, Highlight];
function YooptaEditorComponent() {
// Initial content value
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'Welcome to Yoopta Editor!' }],
},
]);
const editor = useMemo(() => createYooptaEditor(), []);
const selectionRef = useRef(null);
const onChange = (newValue) => {
setValue(newValue);
// You can save the content to your backend or local storage here
};
return (
<div
className="editor-container"
ref={selectionRef}
>
<YooptaEditor
editor={editor}
plugins={plugins}
tools={TOOLS}
marks={MARKS}
selectionBoxRoot={selectionRef}
value={value}
onChange={onChange}
autoFocus
/>
</div>
);
}
export default YooptaEditorComponent;
Step 8: Add Some Basic Styling
Yoopta Editor comes with default minimal styling, but you might want to add some custom styles:
/* Add to your CSS file */
.editor-container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
border: 1px solid #e2e8f0;
border-radius: 8px;
min-height: 300px;
background-color: white;
}
.yoopta-editor {
/* Additional editor styling */
line-height: 1.6;
font-size: 16px;
}
Step 9: Persisting Content
To save the editor content, you can use the onChange
callback to store the content in a database or localStorage:
function YooptaEditorWithPersistence() {
// Load initial content from localStorage or use default
const initialValue = useMemo(() => {
if (typeof window !== 'undefined') {
const savedContent = localStorage.getItem('editorContent');
if (savedContent) {
try {
return JSON.parse(savedContent);
} catch (e) {
console.error('Failed to parse saved content', e);
}
}
}
return [
{
type: 'paragraph',
children: [{ text: 'Start writing here...' }],
},
];
}, []);
const [value, setValue] = useState(initialValue);
const onChange = (newValue) => {
setValue(newValue);
// Save to localStorage
if (typeof window !== 'undefined') {
localStorage.setItem('editorContent', JSON.stringify(newValue));
}
// Or save to a backend API
// saveContentToBackend(newValue);
};
// ...remaining editor setup
}
Advanced Configuration
Custom Toolbar Items
You can customize the toolbar by creating custom toolbar renders:
const CustomToolbarRender = (props) => {
const { tools, editorRef } = props;
return (
<div className="custom-toolbar">
{/* Your custom toolbar UI */}
{tools.map((tool) => (
<button
key={tool.id}
onClick={() => tool.action(editorRef)}
>
{tool.icon}
</button>
))}
</div>
);
};
const TOOLS = {
// ...
Toolbar: {
render: CustomToolbarRender,
tool: Toolbar,
},
// ...
};
Custom Plugin Styling
You can extend plugins to customize their appearance:
const plugins = [
// ...
Divider.extend({
elementProps: {
divider: (props) => ({
...props,
color: '#007aff',
height: '2px',
}),
},
}),
// ...
];
Conclusion
Integrating Yoopta Editor into your Next.js or React application provides a powerful content editing experience with minimal effort. The modular architecture allows you to include only the features you need and customize them to match your application's requirements.
With this setup, you can create everything from simple note-taking applications to complex content management systems with rich media support.
For more detailed information, be sure to check out the Yoopta Editor documentation.
Remember to handle file uploads securely and consider implementing proper data validation both on the client and server sides to ensure your editor implementation remains secure.
📚 Additional Resources
Official Documentation: https://yoopta.dev/
GitHub Repository: https://github.com/yoopta-editor/Yoopta-Editor
Live Examples: https://yoopta-editor.vercel.app/examples/withBaseFullSetup
Editor Source Code: https://github.com/yoopta-editor/Yoopta-Editor/blob/master/web/next-example/src/components/examples/withBaseFullSetup/index.tsx
Happy coding!
This article was generated on May 25, 2025, based on Yoopta Editor version 4.9.7.