Stedefast

Rich Embeds

2 min read

Rich Embeds

/plugin-embeds transforms bare URLs in your Markdown into rich oEmbed content at build time — YouTube videos, Twitter/X posts, GitHub Gists, CodePen pens, Spotify tracks, and Vimeo videos.

Because embedding happens at build time, no client-side JavaScript is needed. The rendered HTML is static.

Live example

Here's a YouTube embed produced by placing a bare URL on its own line:

https://www.youtube.com/watch?v=dQw4w9WgXcQ

Installation

pnpm add /plugin-embeds

Setup

// stedefast.config.ts
import { defineConfig } from "@stedefast/core";
import { EmbedsPlugin } from "/plugin-embeds";

export default defineConfig({
  // ...
  plugins: [
    EmbedsPlugin({
      maxWidth: 720,
      onError: "link",
    }),
  ],
});

Usage

Place a URL on its own line in your Markdown (no surrounding text, no link syntax):

Check out this video:

https://www.youtube.com/watch?v=dQw4w9WgXcQ

And this gist:

https://gist.github.com/octocat/1234567

The plugin detects these "bare URL paragraphs" and replaces them with the provider's oEmbed HTML.

Supported Providers

Provider URL pattern
YouTube youtube.com/watch, youtu.be/
Twitter/X twitter.com/*/status/, x.com/*/status/
GitHub Gist gist.github.com/
CodePen codepen.io/
Spotify open.spotify.com/track/album/playlist/episode/
Vimeo vimeo.com/

Adding Custom Providers

EmbedsPlugin({
  providers: [
    {
      name: "Figma",
      pattern: /https?:\/\/www\.figma\.com\//,
      endpoint: "https://www.figma.com/api/oembed",
      maxWidth: 800,
    },
  ],
})

Custom providers are merged with the built-in list. To replace the built-in list entirely, use overrideProviders.

Options

Option Type Default Description
providers OEmbedProvider[] [] Additional providers merged with built-ins
overrideProviders OEmbedProvider[] Replace all built-in providers
maxWidth number 800 Default max width for embeds
wrapperClass string "sf-embed" CSS class on the wrapper <div>
onError "link" | "skip" | "error" "link" What to do when oEmbed fetch fails

onError behaviour

  • "link" — render a plain <a href> hyperlink (safe fallback)
  • "skip" — leave the URL as a plain paragraph
  • "error" — throw a build error (useful for CI)

Styling

Embeds are wrapped in <div class="sf-embed sf-embed--youtube"> (provider name slugified). Add responsive styles in your theme:

.sf-embed {
  margin: 2rem 0;
}

.sf-embed iframe {
  max-width: 100%;
  aspect-ratio: 16 / 9;
  height: auto;
}

Important Notes

  • Build-time fetches — oEmbed requests are made at stedefast build time. Provider rate limits and network availability apply.
  • allowDangerousHtml — Stedefast's rehype pipeline must have this enabled (it is by default via rehype-raw) for the injected provider HTML to pass through to the output.
  • Twitter embeds — Twitter/X's oEmbed returns a <blockquote> + script. The script call is included in the static HTML; Twitter's JS loads on the client to render the card.