Skip to main content

Embed Plugin

The Embed plugin provides iframe-based embedding for content from popular platforms including video providers, social media, design tools, code playgrounds, and media services.

Installation

npm install @yoopta/embed

Usage

import Embed from '@yoopta/embed';
import { createYooptaEditor } from '@yoopta/editor';

const plugins = [Embed];
const editor = createYooptaEditor({ plugins });

Features

  • Embed content from 12+ popular platforms
  • Automatic URL parsing and provider detection
  • oEmbed protocol support
  • Customizable embed sizes
  • Aspect ratio preservation
  • HTML and Email export with fallbacks
  • Keyboard shortcuts for quick insertion
  • Supports alignment (left, center, right)

Supported Providers

  • Video: YouTube, Vimeo, DailyMotion, Wistia, Loom
  • Social: Twitter, Instagram
  • Design: Figma
  • Code: CodePen, CodeSandbox
  • Media: Spotify, SoundCloud
  • Maps: Google Maps

Options

import type { EmbedPluginOptions } from '@yoopta/embed';

const plugins = [
  Embed.extend({
    options: {
      maxWidth: 1200,
      defaultSizes: {
        width: 650,
        height: 400,
      },
    },
  }),
];

Default Options

{
  type: 'Embed',
  options: {
    display: {
      title: 'Embed',
      description: 'Embed videos, maps, code, and more',
    },
    shortcuts: [
      'embed', 
      'youtube', 
      'vimeo', 
      'twitter', 
      'instagram', 
      'figma', 
      'codepen', 
      'spotify'
    ],
  },
}

Element Type

import type { 
  EmbedElement, 
  EmbedElementProps, 
  EmbedProvider,
  EmbedProviderType,
  EmbedProviderMeta,
} from '@yoopta/embed';

type EmbedProviderType =
  | 'youtube'
  | 'vimeo'
  | 'dailymotion'
  | 'wistia'
  | 'loom'
  | 'twitter'
  | 'figma'
  | 'instagram'
  | 'codepen'
  | 'codesandbox'
  | 'spotify'
  | 'soundcloud'
  | 'google-maps'
  | 'unknown';

type EmbedProviderMeta = {
  title?: string;
  description?: string;
  thumbnailUrl?: string;
  authorName?: string;
  authorUrl?: string;
};

type EmbedProvider = {
  type: EmbedProviderType;
  id: string;
  url: string;
  embedUrl: string;
  meta?: EmbedProviderMeta;
};

type EmbedSizes = {
  width: number;
  height: number;
};

type EmbedElementProps = {
  provider: EmbedProvider | null;
  sizes: EmbedSizes;
  nodeType: 'void';
};

type EmbedElement = SlateElement<'embed', EmbedElementProps>;

Default Props

{
  provider: null,
  sizes: { width: 650, height: 400 },
  nodeType: 'void',
}

Provider Utilities

import {
  parseEmbedUrl,
  detectProvider,
  getProviderConfig,
  getSupportedProviders,
  isEmbedUrl,
  getProviderAspectRatio,
  calculateEmbedDimensions,
  getOEmbedUrl,
  PROVIDER_CONFIGS,
} from '@yoopta/embed';

// Parse URL to extract provider information
const provider = parseEmbedUrl('https://www.youtube.com/watch?v=VIDEO_ID');
// {
//   type: 'youtube',
//   id: 'VIDEO_ID',
//   url: 'https://www.youtube.com/watch?v=VIDEO_ID',
//   embedUrl: 'https://www.youtube.com/embed/VIDEO_ID',
//   meta?: { ... }
// }

// Check if URL is from a supported provider
if (isEmbedUrl(url)) {
  const providerType = detectProvider(url); // 'youtube', 'figma', etc.
}

// Get list of all supported providers
const providers = getSupportedProviders();

// Get aspect ratio for provider
const aspectRatio = getProviderAspectRatio('youtube');
// { width: 16, height: 9 }

// Calculate dimensions maintaining aspect ratio
const dimensions = calculateEmbedDimensions('youtube', 800);
// { width: 800, height: 450 }

oEmbed Support

import { 
  fetchOEmbed, 
  fetchOEmbedViaProxy, 
  extractProviderMeta 
} from '@yoopta/embed';
import type { OEmbedResponse } from '@yoopta/embed';

// Fetch oEmbed data directly
const oembedData: OEmbedResponse = await fetchOEmbed(embedUrl);

// Fetch via proxy (for CORS-restricted providers)
const proxyData = await fetchOEmbedViaProxy(embedUrl, '/api/oembed-proxy');

// Extract metadata from oEmbed response
const meta = extractProviderMeta(oembedData);
// {
//   title: 'Video Title',
//   description: 'Description',
//   thumbnailUrl: 'https://...',
//   authorName: 'Author',
//   authorUrl: 'https://...'
// }

Hooks

useEmbedUrl

import { useEmbedUrl } from '@yoopta/embed';
import type { UseEmbedUrlReturn } from '@yoopta/embed';

function EmbedInput() {
  const { 
    url, 
    provider, 
    isValid, 
    isLoading, 
    error,
    setUrl, 
    clear,
    refresh,
  } = useEmbedUrl();

  return (
    <div>
      <input 
        value={url} 
        onChange={(e) => setUrl(e.target.value)} 
        placeholder="Paste embed URL..."
      />
      {isValid && <p>Provider: {provider?.type}</p>}
      {error && <p>Error: {error}</p>}
    </div>
  );
}

Commands

import { EmbedCommands } from '@yoopta/embed';
import type { EmbedCommandsType } from '@yoopta/embed';

// Insert embed from URL
editor.commands.Embed.insertEmbed({
  url: 'https://www.youtube.com/watch?v=VIDEO_ID',
  sizes: { width: 853, height: 480 },
});

// Update embed sizes
editor.commands.Embed.updateSizes(blockId, {
  width: 1200,
  height: 675,
});

Parsers

HTML

Deserialize: Converts <iframe> or <div data-yoopta-embed> to embed blocks Serialize: Outputs iframe in flex container
<div 
  data-yoopta-embed 
  data-provider="youtube" 
  data-meta-align="center" 
  data-meta-depth="0" 
  style="
    margin-left: 0px; 
    display: flex; 
    width: 100%; 
    justify-content: center;
  ">
  <iframe 
    src="https://www.youtube.com/embed/VIDEO_ID" 
    width="853" 
    height="480" 
    frameborder="0" 
    allowfullscreen
  ></iframe>
</div>

Markdown

Exports as link (Markdown doesn’t support embeds natively):
[Video Title](https://www.youtube.com/watch?v=VIDEO_ID)

Email

Shows thumbnail with link (email clients don’t support iframes):
<table style="width: 100%;">
  <tbody>
    <tr>
      <td style="display: flex; justify-content: center; padding: 1rem 0;">
        <a href="https://www.youtube.com/watch?v=VIDEO_ID" target="_blank">
          <img src="thumbnail.jpg" width="853" height="480" alt="Video Title" />
        </a>
      </td>
    </tr>
  </tbody>
</table>

Examples

Basic YouTube Embed

import { Blocks } from '@yoopta/editor';
import { parseEmbedUrl } from '@yoopta/embed';
import { generateId } from '@yoopta/editor';

const youtubeUrl = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ';
const provider = parseEmbedUrl(youtubeUrl);

Blocks.insertBlock(editor, {
  type: 'Embed',
  value: [
    {
      id: generateId(),
      type: 'embed',
      props: {
        provider,
        sizes: { width: 853, height: 480 },
        nodeType: 'void',
      },
      children: [{ text: '' }],
    },
  ],
});

Figma Embed

const figmaUrl = 'https://www.figma.com/file/abc123/Design-File';
const provider = parseEmbedUrl(figmaUrl);

Blocks.insertBlock(editor, {
  type: 'Embed',
  value: [
    {
      id: generateId(),
      type: 'embed',
      props: {
        provider,
        sizes: { width: 800, height: 600 },
        nodeType: 'void',
      },
      children: [{ text: '' }],
    },
  ],
});

CodePen Embed

const codepenUrl = 'https://codepen.io/username/pen/abc123';
const provider = parseEmbedUrl(codepenUrl);

Blocks.insertBlock(editor, {
  type: 'Embed',
  value: [
    {
      id: generateId(),
      type: 'embed',
      props: {
        provider,
        sizes: { width: 700, height: 500 },
        nodeType: 'void',
      },
      children: [{ text: '' }],
    },
  ],
});

Using Keyboard Shortcuts

Type one of these shortcuts at the start of an empty paragraph:
  • embed + Space → Opens embed URL input
  • youtube + Space → Opens with YouTube hint
  • figma + Space → Opens with Figma hint
  • codepen + Space → Opens with CodePen hint

Dynamic Provider Detection

import { parseEmbedUrl, isEmbedUrl } from '@yoopta/embed';

function handleEmbedUrl(url: string) {
  if (!isEmbedUrl(url)) {
    console.error('Unsupported URL');
    return;
  }

  const provider = parseEmbedUrl(url);
  
  console.log(`Embedding ${provider.type} content`);
  console.log(`Embed URL: ${provider.embedUrl}`);
  
  // Insert embed block...
}

Provider Configurations

import { PROVIDER_CONFIGS } from '@yoopta/embed';
import type { ProviderConfig } from '@yoopta/embed';

// Access provider configurations
const youtubeConfig: ProviderConfig = PROVIDER_CONFIGS.youtube;
// {
//   type: 'youtube',
//   name: 'YouTube',
//   patterns: [/youtube.com/, /youtu.be/],
//   extractId: (url) => ...,
//   buildEmbedUrl: (id, url) => ...,
//   aspectRatio: { width: 16, height: 9 },
//   oEmbedUrl: (url) => ...,
// }

Aspect Ratios

Default aspect ratios for providers:
  • YouTube, Vimeo, DailyMotion, Wistia, Loom: 16:9
  • Twitter, Instagram: 1:1
  • Figma: 4:3
  • CodePen, CodeSandbox: 3:2
  • Spotify: 4:5
  • SoundCloud: 16:9
  • Google Maps: 16:9

Build docs developers (and LLMs) love