Comprehensive media handling capabilities for the Plate rich text editor framework, supporting images, videos, audio files, and embeddable content
—
Support for embedding videos and social media content from major providers including YouTube, Vimeo, Twitter, and more. Provides URL parsing, iframe extraction, and embed element insertion with XSS protection.
Core plugin for handling embeddable media content from external providers.
/**
* Plugin for embeddable media content from external providers
* Handles YouTube, Vimeo, Twitter, and other social media embeds
*/
const BaseMediaEmbedPlugin: TSlatePlugin<MediaEmbedConfig>;
interface MediaEmbedConfig extends MediaPluginOptions {
// Inherits standard media plugin options for URL handling
}Usage Example:
import { BaseMediaEmbedPlugin } from "@udecode/plate-media";
import { createSlateEditor } from "@udecode/plate";
const editor = createSlateEditor({
plugins: [
BaseMediaEmbedPlugin.configure({
options: {
transformUrl: (url) => {
// Add privacy parameters for YouTube embeds
if (url.includes('youtube.com') || url.includes('youtu.be')) {
return url.replace('youtube.com', 'youtube-nocookie.com');
}
return url;
}
}
})
]
});Function for inserting media embed elements into the editor.
/**
* Inserts a media embed element at the current selection
* @param editor - Slate editor instance
* @param element - Partial media embed element with URL
* @param options - Optional insertion configuration
*/
function insertMediaEmbed(
editor: SlateEditor,
element: Partial<TMediaEmbedElement>,
options?: InsertNodesOptions
): void;
interface TMediaEmbedElement {
type: 'media_embed';
url: string;
id?: string;
provider?: string;
}Usage Example:
import { insertMediaEmbed } from "@udecode/plate-media";
// Insert YouTube video
insertMediaEmbed(editor, {
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
});
// Insert Vimeo video
insertMediaEmbed(editor, {
url: "https://vimeo.com/123456789"
});
// Insert with specific position
insertMediaEmbed(editor, {
url: "https://twitter.com/user/status/123456789"
}, {
at: [0, 1] // Insert at specific location
});Comprehensive URL parsing system for extracting embed data from various providers.
/**
* Parses media URLs using provided parsers with XSS protection
* @param url - URL to parse
* @param options - Configuration with URL parsers
* @returns Parsed embed data or undefined if not supported
*/
function parseMediaUrl(
url: string,
options: { urlParsers: EmbedUrlParser[] }
): EmbedUrlData | undefined;
interface EmbedUrlData {
/** Unique identifier for the media content */
id?: string;
/** Service provider name (e.g., 'youtube', 'vimeo') */
provider?: string;
/** Processed embed URL */
url?: string;
}
type EmbedUrlParser = (url: string) => EmbedUrlData | undefined;Usage Example:
import { parseMediaUrl, parseVideoUrl, parseTwitterUrl } from "@udecode/plate-media";
const parsers = [parseVideoUrl, parseTwitterUrl];
const embedData = parseMediaUrl("https://www.youtube.com/watch?v=dQw4w9WgXcQ", {
urlParsers: parsers
});
if (embedData) {
console.log(embedData);
// Output: { id: "dQw4w9WgXcQ", provider: "youtube", url: "https://www.youtube.com/embed/dQw4w9WgXcQ" }
insertMediaEmbed(editor, { url: embedData.url });
}/**
* Parses video URLs from major providers using js-video-url-parser library
* Supports YouTube, Vimeo, Dailymotion, Youku, and Coub
* @param url - Video URL to parse
* @returns Parsed video data or undefined if not supported
*/
function parseVideoUrl(url: string): EmbedUrlData | undefined;
/**
* Supported video providers
*/
const VIDEO_PROVIDERS: string[] = [
'youtube',
'vimeo',
'dailymotion',
'youku',
'coub'
];Usage Examples:
import { parseVideoUrl } from "@udecode/plate-media";
// YouTube URLs
parseVideoUrl("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
parseVideoUrl("https://youtu.be/dQw4w9WgXcQ");
parseVideoUrl("https://m.youtube.com/watch?v=dQw4w9WgXcQ");
// Vimeo URLs
parseVideoUrl("https://vimeo.com/123456789");
parseVideoUrl("https://player.vimeo.com/video/123456789");
// Dailymotion URLs
parseVideoUrl("https://www.dailymotion.com/video/x123456");/**
* Parses Twitter/X URLs and extracts tweet ID
* Supports both twitter.com and x.com domains
* @param url - Twitter URL to parse
* @returns Parsed tweet data or undefined if not a valid tweet URL
*/
function parseTwitterUrl(url: string): EmbedUrlData | undefined;Usage Examples:
import { parseTwitterUrl } from "@udecode/plate-media";
// Twitter URLs
parseTwitterUrl("https://twitter.com/user/status/1234567890");
parseTwitterUrl("https://mobile.twitter.com/user/status/1234567890");
// X URLs
parseTwitterUrl("https://x.com/user/status/1234567890");
// Returns: { id: "1234567890", provider: "twitter", url: "processed_url" }/**
* Extracts URL from iframe embed code or returns clean URL
* Handles iframe src extraction and URL cleanup
* @param url - URL or iframe embed code
* @returns Cleaned URL
*/
function parseIframeUrl(url: string): string;Usage Examples:
import { parseIframeUrl } from "@udecode/plate-media";
// Extract from iframe
parseIframeUrl('<iframe src="https://www.youtube.com/embed/123" width="560" height="315"></iframe>');
// Returns: "https://www.youtube.com/embed/123"
// Clean existing URL
parseIframeUrl("https://www.youtube.com/watch?v=123&feature=share");
// Returns: "https://www.youtube.com/watch?v=123&feature=share"Utilities for handling various types of media content.
/**
* Generic media insertion with URL prompt or custom getter
* Provides a flexible interface for inserting any media type
* @param editor - Slate editor instance
* @param options - Media insertion options
*/
function insertMedia<E extends SlateEditor>(
editor: E,
options?: InsertMediaOptions
): Promise<void>;
interface InsertMediaOptions extends InsertNodesOptions {
/** Media type to insert (defaults to auto-detection) */
type?: string;
/** Custom URL retrieval function (overrides default prompt) */
getUrl?: () => Promise<string>;
}Usage Examples:
import { insertMedia } from "@udecode/plate-media";
// Use default URL prompt
await insertMedia(editor);
// Specify media type
await insertMedia(editor, { type: 'video' });
// Custom URL getter
await insertMedia(editor, {
getUrl: async () => {
// Your custom URL input logic
return await showCustomUrlDialog();
}
});
// Insert at specific location
await insertMedia(editor, {
type: 'image',
at: [0, 0]
});Configuration options for the media embed plugin.
interface MediaEmbedConfig extends MediaPluginOptions {
/** Custom URL validation for embed content */
isUrl?: (text: string) => boolean;
/** URL transformation for embed URLs */
transformUrl?: (url: string) => string;
}Usage Example:
import { BaseMediaEmbedPlugin } from "@udecode/plate-media";
const embedConfig: MediaEmbedConfig = {
isUrl: (text) => {
// Custom validation for embeddable URLs
const embedPatterns = [
/youtube\.com\/watch/,
/youtu\.be\//,
/vimeo\.com\/\d+/,
/twitter\.com\/\w+\/status\/\d+/,
/x\.com\/\w+\/status\/\d+/
];
return embedPatterns.some(pattern => pattern.test(text));
},
transformUrl: (url) => {
// Add parameters for privacy and performance
if (url.includes('youtube.com')) {
const newUrl = new URL(url.replace('youtube.com', 'youtube-nocookie.com'));
newUrl.searchParams.set('rel', '0'); // Don't show related videos
newUrl.searchParams.set('modestbranding', '1'); // Minimal branding
return newUrl.toString();
}
return url;
}
};
const editor = createSlateEditor({
plugins: [
BaseMediaEmbedPlugin.configure({
options: embedConfig
})
]
});The media embed system includes several security features:
parseMediaUrl function includes built-in XSS protectionisUrl functions can validate URLs before processingtransformUrl allows sanitization and modification of URLs before embeddingSecurity Best Practices:
const secureConfig: MediaEmbedConfig = {
isUrl: (text) => {
// Only allow specific trusted domains
const trustedDomains = [
'youtube.com', 'youtu.be', 'youtube-nocookie.com',
'vimeo.com', 'player.vimeo.com',
'twitter.com', 'x.com'
];
try {
const url = new URL(text);
return trustedDomains.some(domain =>
url.hostname === domain || url.hostname.endsWith('.' + domain)
);
} catch {
return false;
}
},
transformUrl: (url) => {
// Sanitize and add security parameters
const cleanUrl = new URL(url);
// Remove potentially dangerous parameters
cleanUrl.searchParams.delete('autoplay');
cleanUrl.searchParams.delete('loop');
return cleanUrl.toString();
}
};Install with Tessl CLI
npx tessl i tessl/npm-udecode--plate-media