Skip to main content

Overview

The Embed plugin provides a universal solution for embedding external content from various platforms. It supports video providers, social media, code sandboxes, music services, and maps — all with automatic URL detection and proper aspect ratio handling.

Installation

npm install @yoopta/embed

Basic Usage

Pass the plugin to createYooptaEditor; do not pass plugins to <YooptaEditor>.
import { useMemo } from 'react';
import YooptaEditor, { createYooptaEditor } from '@yoopta/editor';
import Embed from '@yoopta/embed';

const plugins = [Embed];

export default function Editor() {
  const editor = useMemo(() => createYooptaEditor({ plugins, marks: [] }), []);
  return <YooptaEditor editor={editor} onChange={() => {}} />;
}

Features

  • Universal Embedding: Embed content from 13+ platforms with a single plugin
  • Auto URL Detection: Automatically detects provider from pasted URLs
  • Provider-specific Aspect Ratios: Each provider uses its optimal aspect ratio
  • Resizable: Resize embeds while maintaining aspect ratio
  • oEmbed Support: Fetches metadata from providers that support oEmbed
  • Responsive: Automatically adapts to container width

Supported Providers

YouTube

Videos, Shorts

Vimeo

Videos

Twitter/X

Tweets, Posts

Instagram

Posts, Reels

Spotify

Tracks, Albums, Playlists

SoundCloud

Tracks, Sets

Figma

Files, Prototypes

CodePen

Pens

CodeSandbox

Sandboxes

Loom

Videos

Dailymotion

Videos

Wistia

Videos

Google Maps

Maps, Places

Configuration

import Embed from '@yoopta/embed';

const plugins = [
  Embed.extend({
    options: {
      maxWidth: 800, // Maximum width in pixels
      defaultSizes: {
        width: 650,
        height: 400,
      },
    },
  }),
];

Options

maxWidth
number
default:"650"
Maximum width for embedded content in pixels
defaultSizes
object
Default dimensions for embeds when aspect ratio cannot be determined

Element Props

provider
object | null
Provider information for the embedded content:
{
  type: EmbedProviderType; // 'youtube' | 'vimeo' | 'twitter' | etc.
  id: string;              // Provider-specific content ID
  url: string;             // Original URL
  embedUrl: string;        // URL used in iframe
  meta?: {
    title?: string;
    description?: string;
    thumbnailUrl?: string;
    authorName?: string;
    authorUrl?: string;
  };
}
sizes
object
Embed dimensions: { width: number, height: number }

Provider Types

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

Commands

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

// Insert an embed from URL
EmbedCommands.insertEmbed(editor, {
  url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
});

// Check if URL is supported
const isSupported = EmbedCommands.isEmbedUrl('https://vimeo.com/123456789');

Utility Functions

The Embed plugin exports utility functions for working with embed URLs:
import {
  parseEmbedUrl,
  isEmbedUrl,
  detectProvider,
  getProviderConfig,
  getProviderAspectRatio,
  calculateEmbedDimensions,
  getSupportedProviders,
  PROVIDER_CONFIGS,
} from '@yoopta/embed';

// Parse a URL and get provider info
const provider = parseEmbedUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
// {
//   type: 'youtube',
//   id: 'dQw4w9WgXcQ',
//   url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
//   embedUrl: 'https://www.youtube.com/embed/dQw4w9WgXcQ'
// }

// Check if URL is embeddable
const canEmbed = isEmbedUrl('https://open.spotify.com/track/...');
// true

// Detect provider type
const providerType = detectProvider('https://codepen.io/user/pen/abc123');
// 'codepen'

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

// Calculate dimensions based on max width
const dimensions = calculateEmbedDimensions('youtube', 800);
// { width: 800, height: 450 }

// Get list of supported providers
const providers = getSupportedProviders();
// [{ type: 'youtube', name: 'YouTube' }, ...]

URL Patterns

Each provider supports specific URL patterns:

YouTube

youtube.com/watch?v=VIDEO_ID
youtu.be/VIDEO_ID
youtube.com/embed/VIDEO_ID
youtube.com/shorts/VIDEO_ID

Vimeo

vimeo.com/VIDEO_ID
player.vimeo.com/video/VIDEO_ID

Twitter/X

twitter.com/user/status/TWEET_ID
x.com/user/status/TWEET_ID

Instagram

instagram.com/p/POST_ID
instagram.com/reel/REEL_ID
instagram.com/tv/TV_ID

Spotify

open.spotify.com/track/TRACK_ID
open.spotify.com/album/ALBUM_ID
open.spotify.com/playlist/PLAYLIST_ID
open.spotify.com/episode/EPISODE_ID
open.spotify.com/show/SHOW_ID

Figma

figma.com/file/FILE_ID
figma.com/proto/FILE_ID
figma.com/design/FILE_ID

CodePen

codepen.io/USER/pen/PEN_ID
codepen.io/USER/full/PEN_ID

CodeSandbox

codesandbox.io/s/SANDBOX_ID
codesandbox.io/embed/SANDBOX_ID

Hooks

useEmbedUrl

Parse URLs and fetch oEmbed data:
import { useEmbedUrl } from '@yoopta/embed';

const MyComponent = () => {
  const { provider, oEmbedData, loading, error, embedProps } = useEmbedUrl(
    'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
  );

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <div>
      <p>Provider: {provider?.type}</p>
      <p>Title: {oEmbedData?.title}</p>
      <p>Dimensions: {embedProps.sizes?.width} x {embedProps.sizes?.height}</p>
    </div>
  );
};

Custom Rendering

import Embed from '@yoopta/embed';

const CustomEmbed = Embed.extend({
  elements: {
    embed: {
      render: (props) => {
        const { provider, sizes } = props.element.props;

        if (!provider) {
          return (
            <div {...props.attributes} contentEditable={false}>
              <div className="embed-placeholder">
                Enter a URL to embed content
              </div>
              {props.children}
            </div>
          );
        }

        return (
          <div {...props.attributes} contentEditable={false}>
            <div className="embed-wrapper" style={{ maxWidth: sizes.width }}>
              <iframe
                src={provider.embedUrl}
                width={sizes.width}
                height={sizes.height}
                frameBorder="0"
                allowFullScreen
                title={provider.meta?.title || provider.type}
              />
            </div>
            {props.children}
          </div>
        );
      },
    },
  },
});

With Shadcn Theme

import Embed from '@yoopta/embed';
import { EmbedUI } from '@yoopta/themes-shadcn';

const plugins = [
  Embed.extend({
    elements: EmbedUI,
    options: {
      maxWidth: 800,
    },
  }),
];

Parsers

HTML Deserialization

The plugin automatically deserializes <iframe> elements with supported URLs:
<iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ" width="650" height="400"></iframe>
It also handles divs with the data-yoopta-embed attribute:
<div data-yoopta-embed data-provider="youtube">
  <iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ" width="650" height="400"></iframe>
</div>

HTML Serialization

<div data-yoopta-embed data-provider="youtube" style="display: flex; justify-content: center;">
  <iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ" width="650" height="366" frameborder="0" allowfullscreen></iframe>
</div>

Markdown Serialization

Embeds are serialized as links in Markdown:
[YouTube](https://www.youtube.com/watch?v=dQw4w9WgXcQ)

Email Serialization

For email clients that don’t support iframes, embeds are rendered as clickable thumbnails (when available) or placeholder links:
<a href="https://www.youtube.com/watch?v=..." target="_blank">
  <img src="thumbnail_url" alt="Video title" />
</a>

Aspect Ratios

Each provider has its optimal aspect ratio:
ProviderAspect Ratio
YouTube16:9
Vimeo16:9
Dailymotion16:9
Loom16:9
Wistia16:9
Figma16:9
CodePen16:9
CodeSandbox16:9
Google Maps16:9
Twitter550:600
Instagram1:1
Spotify300:380
SoundCloud100:166

Use Cases

Blog Posts

Embed YouTube tutorials, Spotify playlists, or tweets

Documentation

Include Figma designs, CodePen demos, or Loom walkthroughs

Portfolio

Showcase Vimeo videos, Dribbble shots, or CodeSandbox projects

Social Content

Embed Instagram posts, Twitter threads, or TikTok videos

Music & Audio

Include Spotify tracks, SoundCloud sets, or podcast episodes

Development

Share CodePen experiments, CodeSandbox demos, or GitHub gists

Best Practices

Choose the right provider for your content type. Use Video plugin for self-hosted videos, Embed plugin for third-party content.
Embeds load external content which can affect page performance. Consider lazy loading for content-heavy pages.
Some embeds may not load due to privacy settings or content restrictions. Consider providing fallback content or links.
Some platforms have embedding restrictions. Check provider policies for commercial use.
Configure appropriate maxWidth for your design to maintain consistency across embed types.

Troubleshooting

If a URL is not being detected, check:
  1. The URL format matches supported patterns
  2. The URL is from a supported provider
Solution: Use the parseEmbedUrl utility to debug:
import { parseEmbedUrl } from '@yoopta/embed';
const provider = parseEmbedUrl('your-url-here');
console.log(provider); // Check if provider is not null
Some content may be blocked due to:
  1. Content is private or restricted
  2. Platform blocks embedding from your domain
  3. CORS restrictions
Solution: Check the provider’s embedding policies and ensure content is publicly embeddable.
If the aspect ratio looks wrong:
  1. The provider may have changed their default dimensions
  2. The content may have a non-standard aspect ratio
Solution: Resize the embed manually using the resize handles.
Not all providers support oEmbed. The plugin will still work but may not have:
  1. Thumbnail images
  2. Title/description metadata
  3. Author information
Solution: This is expected behavior. The embed will still function correctly.

Embed vs Video Plugin

FeatureEmbed PluginVideo Plugin
Self-hosted videos
YouTube/Vimeo
File upload
Social media
Code sandboxes
Music services
Maps
Playback settings
Poster images
Recommendation: Use the Video plugin for self-hosted videos or when you need playback controls. Use the Embed plugin for third-party content from social media, code sandboxes, music services, and maps.