Color mode

Rich Embed

Build-time media embeds for ```embed code blocks.

日本語

Overview

richEmbed() turns an ```embed fenced code block into a responsive <figure class="rb-rich-embed">. Provider detection is pure string inspection: the plugin never performs a network request at build time, and it ships no client-side JavaScript.

Usage

ts
import { defineConfig } from "@riebeckite/core";
import { richEmbed } from "@riebeckite/plugin-rich-embed";
 
export default defineConfig({
  // ...
  plugins: [
    richEmbed({
      allowHosts: ["player.example.com"],
    }),
  ],
});

Syntax

The first non-empty line is the URL. Every following key: value line is an option.

md
```embed
https://www.youtube.com/watch?v=dQw4w9WgXcQ
title: Demo video
caption: A short caption under the frame
aspect: 16/9
start: 30
```
Block option Description
title title attribute of the <iframe> (also the link label for Gist)
caption Rendered as <figcaption class="rb-rich-embed__caption">
aspect Aspect ratio such as 16/9 or 4/3 (default 16/9)
start Start time in seconds (YouTube only)

Unknown option keys are ignored. An invalid aspect falls back to 16/9.

Supported providers

Provider Recognised URLs Output src
YouTube youtube.com/watch?v=, youtu.be/, /shorts/, /embed/, /live/ https://www.youtube-nocookie.com/embed/<id>
Vimeo vimeo.com/<numeric id> https://player.vimeo.com/video/<id>
Spotify open.spotify.com/(track|album|playlist|episode|show)/<id> https://open.spotify.com/embed/<type>/<id>
CodePen codepen.io/<user>/pen/<id> https://codepen.io/<user>/embed/<id>
GitHub Gist gist.github.com/... link card (gists cannot be iframed)

When the host is not recognised, the block is left untouched and a warning diagnostic is emitted. A generic <iframe> is only produced when the host is listed in allowHosts.

Options

Option Type Default Description
allowHosts string[] [] Hostnames allowed to use the generic iframe fallback
providers RichEmbedProvider[] all Allowlist of providers to enable
disable RichEmbedProvider[] [] Providers to disable (wins over providers)

Output HTML

html
<figure
  class="rb-rich-embed"
  data-rich-embed="youtube"
  data-rich-embed-marker="RIEBECKITE_EXTERNAL_RICHEMBED_MARKER"
>
  <div class="rb-rich-embed__frame" style="--rb-rich-embed-aspect:16/9">
    <iframe
      src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ"
      loading="lazy"
      allowfullscreen
      referrerpolicy="strict-origin-when-cross-origin"
      title="Demo video"
    ></iframe>
  </div>
  <figcaption class="rb-rich-embed__caption">A short caption</figcaption>
</figure>

Gist blocks produce div.rb-rich-embed__card > a.rb-rich-embed__link instead of an iframe.

CSS hooks

  • .rb-rich-embed — outer figure
  • .rb-rich-embed__frame — responsive wrapper (reads --rb-rich-embed-aspect)
  • .rb-rich-embed__caption — optional caption
  • .rb-rich-embed__card, .rb-rich-embed__link — Gist link card

The stylesheet is shipped as @riebeckite/plugin-rich-embed/style.css.

Diagnostics

Unsupported or invalid blocks keep their original code block and report a warning through the vfile message channel:

  • source: "@riebeckite/plugin-rich-embed"
  • ruleId: "unsupported-embed"

Security

  • Only https: URLs are accepted.
  • Provider output is constructed from validated path segments; dynamic segments are passed through encodeURIComponent.
  • A generic iframe requires an explicit allowHosts entry.
  • No raw user HTML is ever emitted: titles, captions, and labels are written as escaped text nodes.

Limitations

  • No OEMBED fetching or title/thumbnail discovery — everything is derived from the URL and the block options.
  • GitHub Gists cannot be embedded in an iframe, so they render as a link card.
  • Generic embeds are emitted verbatim from the https: URL, so only allow hosts you trust.

Exports

  • richEmbed(options?) — plugin factory
  • richEmbedPlugin — alias of richEmbed
  • Types: RichEmbedOptions, RichEmbedProvider

See also

History

1 changesCollapseExpand
1 + <!-- Generated from packages/plugins/rich-embed/README.md. Do not edit this page directly; edit the package README and run `pnpm docs:sync`. -->
2 +
3 + # Rich Embed
4 +
5 + Build-time media embeds for ` ```embed ` code blocks.
6 +
7 + [日本語](./rich-embed.md)
8 +
9 + ## Overview
10 +
11 + `richEmbed()` turns an ` ```embed ` fenced code block into a responsive
12 + `<figure class="rb-rich-embed">`. Provider detection is pure string inspection:
13 + the plugin never performs a network request at build time, and it ships no
14 + client-side JavaScript.
15 +
16 + ## Usage
17 +
18 + ```ts
19 + import { defineConfig } from "@riebeckite/core";
20 + import { richEmbed } from "@riebeckite/plugin-rich-embed";
21 +
22 + export default defineConfig({
23 + // ...
24 + plugins: [
25 + richEmbed({
26 + allowHosts: ["player.example.com"],
27 + }),
28 + ],
29 + });
30 + ```
31 +
32 + ## Syntax
33 +
34 + The first non-empty line is the URL. Every following `key: value` line is an
35 + option.
36 +
37 + ````md
38 + ```embed
39 + https://www.youtube.com/watch?v=dQw4w9WgXcQ
40 + title: Demo video
41 + caption: A short caption under the frame
42 + aspect: 16/9
43 + start: 30
44 + ```
45 + ````
46 +
47 + | Block option | Description |
48 + | ------------ | ----------- |
49 + | `title` | `title` attribute of the `<iframe>` (also the link label for Gist) |
50 + | `caption` | Rendered as `<figcaption class="rb-rich-embed__caption">` |
51 + | `aspect` | Aspect ratio such as `16/9` or `4/3` (default `16/9`) |
52 + | `start` | Start time in seconds (YouTube only) |
53 +
54 + Unknown option keys are ignored. An invalid `aspect` falls back to `16/9`.
55 +
56 + ## Supported providers
57 +
58 + | Provider | Recognised URLs | Output `src` |
59 + | -------- | --------------- | ------------ |
60 + | YouTube | `youtube.com/watch?v=`, `youtu.be/`, `/shorts/`, `/embed/`, `/live/` | `https://www.youtube-nocookie.com/embed/<id>` |
61 + | Vimeo | `vimeo.com/<numeric id>` | `https://player.vimeo.com/video/<id>` |
62 + | Spotify | `open.spotify.com/(track\|album\|playlist\|episode\|show)/<id>` | `https://open.spotify.com/embed/<type>/<id>` |
63 + | CodePen | `codepen.io/<user>/pen/<id>` | `https://codepen.io/<user>/embed/<id>` |
64 + | GitHub Gist | `gist.github.com/...` | link card (gists cannot be iframed) |
65 +
66 + When the host is not recognised, the block is left untouched and a warning
67 + diagnostic is emitted. A generic `<iframe>` is only produced when the host is
68 + listed in `allowHosts`.
69 +
70 + ## Options
71 +
72 + | Option | Type | Default | Description |
73 + | ------ | ---- | ------- | ----------- |
74 + | `allowHosts` | `string[]` | `[]` | Hostnames allowed to use the generic iframe fallback |
75 + | `providers` | `RichEmbedProvider[]` | all | Allowlist of providers to enable |
76 + | `disable` | `RichEmbedProvider[]` | `[]` | Providers to disable (wins over `providers`) |
77 +
78 + ## Output HTML
79 +
80 + ```html
81 + <figure
82 + class="rb-rich-embed"
83 + data-rich-embed="youtube"
84 + data-rich-embed-marker="RIEBECKITE_EXTERNAL_RICHEMBED_MARKER"
85 + >
86 + <div class="rb-rich-embed__frame" style="--rb-rich-embed-aspect:16/9">
87 + <iframe
88 + src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ"
89 + loading="lazy"
90 + allowfullscreen
91 + referrerpolicy="strict-origin-when-cross-origin"
92 + title="Demo video"
93 + ></iframe>
94 + </div>
95 + <figcaption class="rb-rich-embed__caption">A short caption</figcaption>
96 + </figure>
97 + ```
98 +
99 + Gist blocks produce `div.rb-rich-embed__card > a.rb-rich-embed__link` instead of
100 + an iframe.
101 +
102 + ### CSS hooks
103 +
104 + - `.rb-rich-embed` — outer figure
105 + - `.rb-rich-embed__frame` — responsive wrapper (reads `--rb-rich-embed-aspect`)
106 + - `.rb-rich-embed__caption` — optional caption
107 + - `.rb-rich-embed__card`, `.rb-rich-embed__link` — Gist link card
108 +
109 + The stylesheet is shipped as `@riebeckite/plugin-rich-embed/style.css`.
110 +
111 + ## Diagnostics
112 +
113 + Unsupported or invalid blocks keep their original code block and report a
114 + warning through the vfile message channel:
115 +
116 + - `source: "@riebeckite/plugin-rich-embed"`
117 + - `ruleId: "unsupported-embed"`
118 +
119 + ## Security
120 +
121 + - Only `https:` URLs are accepted.
122 + - Provider output is constructed from validated path segments; dynamic
123 + segments are passed through `encodeURIComponent`.
124 + - A generic iframe requires an explicit `allowHosts` entry.
125 + - No raw user HTML is ever emitted: titles, captions, and labels are written as
126 + escaped text nodes.
127 +
128 + ## Limitations
129 +
130 + - No OEMBED fetching or title/thumbnail discovery — everything is derived from
131 + the URL and the block options.
132 + - GitHub Gists cannot be embedded in an iframe, so they render as a link card.
133 + - Generic embeds are emitted verbatim from the `https:` URL, so only allow hosts
134 + you trust.
135 +
136 + ## Exports
137 +
138 + - `richEmbed(options?)` — plugin factory
139 + - `richEmbedPlugin` — alias of `richEmbed`
140 + - Types: `RichEmbedOptions`, `RichEmbedProvider`
141 +
142 + ## See also
143 +
144 + - [Plugin guide](../reference/plugin-api.en.md)
145 +