Media
'use client';
import React from 'react';
import { Plate } from '@udecode/plate-common/react';
import { editorPlugins } from '@/components/editor/plugins/editor-plugins';
import { useCreateEditor } from '@/components/editor/use-create-editor';
import { Editor, EditorContainer } from '@/components/plate-ui/editor';
import { DEMO_VALUES } from './values/demo-values';
export default function Demo({ id }: { id: string }) {
const editor = useCreateEditor({
plugins: [...editorPlugins],
value: DEMO_VALUES[id],
});
return (
<Plate editor={editor}>
<EditorContainer variant="demo">
<Editor />
</EditorContainer>
</Plate>
);
}
Features
Media Features
- Editable captions
- Resizable elements
Media Support
- File types:
- Image
- Video
- Audio
- Others (PDF, Word, etc.)
- Video providers:
- Local video files
- YouTube, Vimeo, Dailymotion, Youku, Coub
- Embed providers:
- Tweets
Upload
- Multiple upload methods:
- Toolbar button with file picker
- Drag and drop from file system
- Paste from clipboard (images)
- URL embedding for external media
- Upload experience:
- Real-time progress tracking
- Preview during upload
- Automatically converts the placeholder to the appropriate media element (image, video, audio, file) once the upload or embed is submitted
- Error handling
- File size validation
- Type validation
Installation
npm install @udecode/plate-media
Usage
import {
AudioPlugin,
FilePlugin,
ImagePlugin,
MediaEmbedPlugin,
PlaceholderPlugin,
VideoPlugin,
} from '@udecode/plate-media/react';
import { SelectOnBackspacePlugin } from '@udecode/plate-select';
const plugins = [
// ...otherPlugins,
ImagePlugin,
VideoPlugin,
AudioPlugin,
FilePlugin,
MediaEmbedPlugin,
SelectOnBackspacePlugin.configure({
options: {
query: {
allow: [ImagePlugin.key, VideoPlugin.key, AudioPlugin.key, FilePlugin.key, MediaEmbedPlugin.key],
},
},
}),
PlaceholderPlugin.configure({
options: { disableEmptyPlaceholder: true },
render: { afterEditable: MediaUploadToast },
}),
];
const components = {
// ...otherComponents,
[ImagePlugin.key]: ImageElement,
[VideoPlugin.key]: VideoElement,
[AudioPlugin.key]: AudioElement,
[FilePlugin.key]: FileElement,
[MediaEmbedPlugin.key]: MediaEmbedElement,
[PlaceholderPlugin.key]: MediaPlaceholderElement,
};
Caption
To enable media captions, use the Caption Plugin.
Upload
There are two ways to implement file uploads in your editor:
- Using our UploadThing implementation
- Creating a custom implementation with your preferred upload solution
UploadThing
-
Add MediaPlaceholderElement component
-
Add API routes for UploadThing:
npx shadcx@latest add plate/api-uploadthing
- Get your secret key from UploadThing for free
- Add your UploadThing secret key to
.env
:
UPLOADTHING_TOKEN=xxx
Custom Implementation
For custom implementations, you'll need to create an upload hook that matches our interface. This can work with any upload backend (AWS S3, UploadThing, Cloudinary, Firebase Storage, etc.).
The upload hook should implement this interface:
interface UseUploadFileProps {
onUploadComplete?: (file: UploadedFile) => void;
onUploadError?: (error: unknown) => void;
headers?: Record<string, string>;
onUploadBegin?: (fileName: string) => void;
onUploadProgress?: (progress: { progress: number }) => void;
skipPolling?: boolean;
}
interface UploadedFile {
key: string; // Unique identifier
url: string; // Public URL of the uploaded file
name: string; // Original filename
size: number; // File size in bytes
type: string; // MIME type
}
Example implementation with S3 presigned URLs:
export function useUploadFile({
onUploadComplete,
onUploadError,
onUploadProgress
}: UseUploadFileProps = {}) {
const [uploadedFile, setUploadedFile] = useState<UploadedFile>();
const [uploadingFile, setUploadingFile] = useState<File>();
const [progress, setProgress] = useState(0);
const [isUploading, setIsUploading] = useState(false);
async function uploadFile(file: File) {
setIsUploading(true);
setUploadingFile(file);
try {
// Get presigned URL and final URL from your backend
const { presignedUrl, fileUrl, fileKey } = await fetch('/api/upload', {
method: 'POST',
body: JSON.stringify({
filename: file.name,
contentType: file.type,
}),
}).then(r => r.json());
// Upload to S3 using presigned URL
await axios.put(presignedUrl, file, {
headers: { 'Content-Type': file.type },
onUploadProgress: (progressEvent) => {
const progress = (progressEvent.loaded / progressEvent.total) * 100;
setProgress(progress);
onUploadProgress?.({ progress });
},
});
const uploadedFile = {
key: fileKey,
url: fileUrl,
name: file.name,
size: file.size,
type: file.type,
};
setUploadedFile(uploadedFile);
onUploadComplete?.(uploadedFile);
return uploadedFile;
} catch (error) {
onUploadError?.(error);
throw error;
} finally {
setProgress(0);
setIsUploading(false);
setUploadingFile(undefined);
}
}
return {
isUploading,
progress,
uploadFile,
uploadedFile,
uploadingFile,
};
}
Examples
Plate UI
Refer to the preview above.
Plate Plus
Plugins
PlaceholderPlugin
Plugin for void media placeholder elements. Handles file uploads, drag & drop, and clipboard paste events.
Options
- Default:
false
- Default:
false
- Default:
5
- Default:
true
Configuration for different file types. Default configuration:
{
audio: {
maxFileCount: 1,
maxFileSize: '8MB',
mediaType: AudioPlugin.key,
minFileCount: 1,
},
blob: {
maxFileCount: 1,
maxFileSize: '8MB',
mediaType: FilePlugin.key,
minFileCount: 1,
},
image: {
maxFileCount: 3,
maxFileSize: '4MB',
mediaType: ImagePlugin.key,
minFileCount: 1,
},
pdf: {
maxFileCount: 1,
maxFileSize: '4MB',
mediaType: FilePlugin.key,
minFileCount: 1,
},
text: {
maxFileCount: 1,
maxFileSize: '64KB',
mediaType: FilePlugin.key,
minFileCount: 1,
},
video: {
maxFileCount: 1,
maxFileSize: '16MB',
mediaType: VideoPlugin.key,
minFileCount: 1,
},
}
Supported file types: 'image' | 'video' | 'audio' | 'pdf' | 'text' | 'blob'
Disable empty placeholder when no file is uploading.
Disable drag and drop file upload functionality.
Maximum number of files that can be uploaded at once, if not specified by uploadConfig
.
Allow multiple files of the same type to be uploaded.
MediaPluginOptions
Plugin options used by media plugins.
Attributes
A function to check whether a text string is a URL.
A function to transform the URL.
ImagePlugin
Plugin for void image elements. Options extends MediaPluginOptions.
Options
- A data URL (string) from
FileReader.readAsDataURL
- An ArrayBuffer from clipboard data
- A URL string to the uploaded image
- The original data URL/ArrayBuffer if no upload is needed
Extends MediaPluginOptions.
An optional method that will upload the image to a server. The method receives either:
Should return either:
If not provided, the original data URL/ArrayBuffer will be used as the image source.
Disables file upload on data insertion if set to true.
Disables URL embed on data insertion if set to true.
VideoPlugin
Plugin for void video elements.
AudioPlugin
Plugin for void audio elements.
FilePlugin
Plugin for void file elements.
MediaEmbedPlugin
Plugin for void media embed elements. Options extends MediaPluginOptions
.
API Placeholder
editor.tf.insert.media()
Inserts media files into the editor with upload placeholders.
Parameters
Files to upload. Validates against configured file types and limits.
The transform:
- Validates files against configured limits (size, count, type)
- Creates placeholder elements for each file
- Handles multiple file uploads sequentially
- Maintains upload history for undo/redo operations
- Triggers error handling if validation fails
Error codes:
enum UploadErrorCode {
INVALID_FILE_TYPE = 400,
TOO_MANY_FILES = 402,
INVALID_FILE_SIZE = 403,
TOO_LESS_FILES = 405,
TOO_LARGE = 413,
}
editor.tf.insert.audioPlaceholder
Inserts a placeholder. Converts to an audio element when completed.
Parameters
Options for the insert nodes transform.
editor.tf.insert.filePlaceholder
Inserts a placeholder. Converts to a file element when completed.
Parameters
Options for the insert nodes transform.
editor.tf.insert.imagePlaceholder
Inserts a placeholder. Converts to an image element when completed.
Parameters
Options for the insert nodes transform.
editor.tf.insert.videoPlaceholder
Inserts a placeholder. Converts to a video element when completed.
Parameters
Options for the insert nodes transform.
editor.api.placeholder.addUploadingFile()
Tracks a file that is currently being uploaded.
Parameters
Unique identifier for the placeholder element.
The file being uploaded.
editor.api.placeholder.getUploadingFile()
Gets a file that is currently being uploaded.
Parameters
Unique identifier for the placeholder element.
Returns
The uploading file if found, undefined otherwise.
editor.api.placeholder.removeUploadingFile()
Removes a file from the uploading tracking state after upload completes or fails.
Parameters
Unique identifier for the placeholder element to remove.
API Media
parseMediaUrl
Parses a media URL and returns the data associated with it based on the configured rules of the media plugin.
Parameters
The editor instance.
submitFloatingMedia
Submits the floating media element by setting its URL and performing necessary transformations.
Parameters
The editor instance.
EmbedUrlData
A type defining the data returned from parsing an embed URL.
Attributes
The URL of the embedded content.
The provider of the embedded content.
The unique ID for the embedded content.
The component to be rendered for the embedded content.
API Image
insertImage
Inserts an image element into the editor.
Parameters
The editor instance.
The URL or ArrayBuffer of the image.
Additional options for inserting the image element.
isImageUrl
Checks if a given URL is a valid image URL.
Parameters
The URL to check.
withImageUpload
Enhances the editor to support pasting images from the clipboard.
Parameters
The editor instance.
The plate plugin.
withImageEmbed
Enhances the editor to automatically insert an image when a URL is pasted.
Parameters
The editor instance.
The plate plugin.
API Media Embed
insertMediaEmbed
Inserts a media embed element at the current selection.
Parameters
The editor instance.
The options for inserting nodes.
parseIframeUrl
Parses the URL of an iframe embed.
Parameters
The URL or embed code of the iframe.
parseTwitterUrl
Parses a Twitter URL and extracts the tweet ID.
Parameters
The Twitter URL.
Returns
An object containing the tweet ID and provider if the parsing is successful. Returns undefined if the URL is not valid or does not match any supported video providers.
parseVideoUrl
Parses a video URL and extracts the video ID and provider-specific embed URL.
Parameters
The video URL.
Returns
An object containing the video ID and provider if the parsing is successful. Returns undefined if the URL is not valid or does not match any supported video providers.
API Components
useResizable
A behavior hook for resizable elements.
State
The alignment of the content within the resizable element.
The minimum width that the resizable element can be adjusted to.
The maximum width that the resizable element can be adjusted to.
A function to set the width of the node, which is used when resizing.
A function to set the width of the resizable element directly.
The current width of the resizable element. This can be a string (e.g., a percentage or 'auto') or a number (representing pixels).
Returns
A React reference to the outermost div wrapping the resizable element.
Props to be spread on the outermost div wrapping the resizable element.
Props to be spread on the resizable element.
useFloatingMediaEditButton
A behavior hook for a floating media edit button.
Returns
useFloatingMediaUrlInput
A behavior hook for a floating media URL input.
Props
The default value for the URL input field.
Returns
useImage
A behavior hook for an image element.
Returns
useMediaState
A state hook for a media element.
Parameters
Returns
The alignment of the media element.
Whether the media element is currently focused.
Whether the media element is currently selected.
Whether the editor is in read-only mode.
The parsed embed data of the media element.
Whether the media element is a tweet.
Whether the media element is a video.
Whether the media element is a YouTube video.
useMediaToolbarButton
A behavior hook for a media toolbar button.
Parameters
Returns
Types
TMediaElement
export interface TMediaElement extends TElement {
url: string;
id?: string;
align?: 'center' | 'left' | 'right';
isUpload?: boolean;
name?: string;
placeholderId?: string;
}
TPlaceholderElement
export interface TPlaceholderElement extends TElement {
mediaType: string;
}