Video and lite embed
Preview Available in release assets
Show authored video behind an explicit activation boundary so third-party embed code makes no request before the visitor chooses to load it.
Video and lite embed primary example
<figure class="thin-video-embed"
data-video-src="https://media.example/embed/launch-film"
data-video-title="Launch film"
data-video-allow="fullscreen"
data-video-allowfullscreen>
<div data-video-stage>
<img src="/media/launch-film-poster.webp" alt="" width="1600" height="900" loading="lazy" decoding="async">
<button type="button" data-video-activate aria-label="Play Launch film">Play video</button>
</div>
<figcaption>
Launch film, 2 minutes. <a href="https://media.example/watch/launch-film">Watch on the media host</a>.
</figcaption>
<details>
<summary>Transcript</summary>
<p>Provide the complete authored transcript here.</p>
</details>
</figure>Show code
<figure class="thin-video-embed"
data-video-src="https://media.example/embed/launch-film"
data-video-title="Launch film"
data-video-allow="fullscreen"
data-video-allowfullscreen>
<div data-video-stage>
<img src="/media/launch-film-poster.webp" alt="" width="1600" height="900" loading="lazy" decoding="async">
<button type="button" data-video-activate aria-label="Play Launch film">Play video</button>
</div>
<figcaption>
Launch film, 2 minutes. <a href="https://media.example/watch/launch-film">Watch on the media host</a>.
</figcaption>
<details>
<summary>Transcript</summary>
<p>Provide the complete authored transcript here.</p>
</details>
</figure>Variant gallery
Each authored example uses the production assets and includes copyable markup.
Consent-gated captioned player
Activate the named Play button to create the player iframe. The local native player supplies a sample caption track and makes no video request before activation. Replace its source and captions together for your own content.
<figure class="thin-video-embed" data-video-src="/examples/video-player/" data-video-title="Moving square clip" style="--thin-video-ratio: 16 / 9; overflow-wrap: anywhere">
<div data-video-stage>
<svg viewBox="0 0 640 360" aria-hidden="true" style="inline-size: 100%; block-size: 100%">
<rect width="640" height="360" fill="#24415c"/>
<circle cx="320" cy="180" r="80" fill="#416c89"/>
</svg>
<button type="button" data-video-activate aria-label="Play moving square clip">
<svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true">
<path fill="currentColor" d="M6 3 21 12 6 21Z"/>
</svg>
</button>
</div>
<figcaption>Moving square clip. <a href="/examples/video-player/">Open the captioned player directly</a>. The local sample has no audio.</figcaption>
<details>
<summary>Transcript and visual description</summary>
<p>A light blue square moves from left to right across a dark blue background. There is no audio.</p>
</details>
</figure>
<script type="module">
import { enhanceVideoEmbeds } from "/behaviors.js";
enhanceVideoEmbeds(document);
</script>Show code
<figure class="thin-video-embed" data-video-src="/examples/video-player/" data-video-title="Moving square clip" style="--thin-video-ratio: 16 / 9; overflow-wrap: anywhere">
<div data-video-stage>
<svg viewBox="0 0 640 360" aria-hidden="true" style="inline-size: 100%; block-size: 100%">
<rect width="640" height="360" fill="#24415c"/>
<circle cx="320" cy="180" r="80" fill="#416c89"/>
</svg>
<button type="button" data-video-activate aria-label="Play moving square clip">
<svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true">
<path fill="currentColor" d="M6 3 21 12 6 21Z"/>
</svg>
</button>
</div>
<figcaption>Moving square clip. <a href="/examples/video-player/">Open the captioned player directly</a>. The local sample has no audio.</figcaption>
<details>
<summary>Transcript and visual description</summary>
<p>A light blue square moves from left to right across a dark blue background. There is no audio.</p>
</details>
</figure>
<script type="module">
import { enhanceVideoEmbeds } from "/behaviors.js";
enhanceVideoEmbeds(document);
</script>Authored four-by-three ratio
The public --thin-video-ratio property changes the poster and player stage without changing activation or the durable destination.
<figure class="thin-video-embed" data-video-src="/examples/video-player/" data-video-title="Moving square clip" style="--thin-video-ratio: 4 / 3; overflow-wrap: anywhere">
<div data-video-stage>
<svg viewBox="0 0 640 360" aria-hidden="true" style="inline-size: 100%; block-size: 100%">
<rect width="640" height="360" fill="#24415c"/>
<circle cx="320" cy="180" r="80" fill="#416c89"/>
</svg>
<button type="button" data-video-activate aria-label="Play moving square clip">
<svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true">
<path fill="currentColor" d="M6 3 21 12 6 21Z"/>
</svg>
</button>
</div>
<figcaption>Moving square clip. <a href="/examples/video-player/">Open the captioned player directly</a>. The local sample has no audio.</figcaption>
<details>
<summary>Transcript and visual description</summary>
<p>A light blue square moves from left to right across a dark blue background. There is no audio.</p>
</details>
</figure>
<script type="module">
import { enhanceVideoEmbeds } from "/behaviors.js";
enhanceVideoEmbeds(document);
</script>Show code
<figure class="thin-video-embed" data-video-src="/examples/video-player/" data-video-title="Moving square clip" style="--thin-video-ratio: 4 / 3; overflow-wrap: anywhere">
<div data-video-stage>
<svg viewBox="0 0 640 360" aria-hidden="true" style="inline-size: 100%; block-size: 100%">
<rect width="640" height="360" fill="#24415c"/>
<circle cx="320" cy="180" r="80" fill="#416c89"/>
</svg>
<button type="button" data-video-activate aria-label="Play moving square clip">
<svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true">
<path fill="currentColor" d="M6 3 21 12 6 21Z"/>
</svg>
</button>
</div>
<figcaption>Moving square clip. <a href="/examples/video-player/">Open the captioned player directly</a>. The local sample has no audio.</figcaption>
<details>
<summary>Transcript and visual description</summary>
<p>A light blue square moves from left to right across a dark blue background. There is no audio.</p>
</details>
</figure>
<script type="module">
import { enhanceVideoEmbeds } from "/behaviors.js";
enhanceVideoEmbeds(document);
</script>Transcript available before playback
Open the ordinary disclosure to read the complete description without loading a player or running JavaScript.
<figure class="thin-video-embed" data-video-src="/examples/video-player/" data-video-title="Moving square clip" style="--thin-video-ratio: 16 / 9; overflow-wrap: anywhere">
<div data-video-stage>
<svg viewBox="0 0 640 360" aria-hidden="true" style="inline-size: 100%; block-size: 100%">
<rect width="640" height="360" fill="#24415c"/>
<circle cx="320" cy="180" r="80" fill="#416c89"/>
</svg>
<button type="button" data-video-activate aria-label="Play moving square clip">
<svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true">
<path fill="currentColor" d="M6 3 21 12 6 21Z"/>
</svg>
</button>
</div>
<figcaption>Moving square clip. <a href="/examples/video-player/">Open the captioned player directly</a>. The local sample has no audio.</figcaption>
<details>
<summary>Transcript and visual description</summary>
<p>A light blue square moves from left to right across a dark blue background. There is no audio.</p>
</details>
</figure>
<script type="module">
import { enhanceVideoEmbeds } from "/behaviors.js";
enhanceVideoEmbeds(document);
</script>Show code
<figure class="thin-video-embed" data-video-src="/examples/video-player/" data-video-title="Moving square clip" style="--thin-video-ratio: 16 / 9; overflow-wrap: anywhere">
<div data-video-stage>
<svg viewBox="0 0 640 360" aria-hidden="true" style="inline-size: 100%; block-size: 100%">
<rect width="640" height="360" fill="#24415c"/>
<circle cx="320" cy="180" r="80" fill="#416c89"/>
</svg>
<button type="button" data-video-activate aria-label="Play moving square clip">
<svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true">
<path fill="currentColor" d="M6 3 21 12 6 21Z"/>
</svg>
</button>
</div>
<figcaption>Moving square clip. <a href="/examples/video-player/">Open the captioned player directly</a>. The local sample has no audio.</figcaption>
<details>
<summary>Transcript and visual description</summary>
<p>A light blue square moves from left to right across a dark blue background. There is no audio.</p>
</details>
</figure>
<script type="module">
import { enhanceVideoEmbeds } from "/behaviors.js";
enhanceVideoEmbeds(document);
</script>Anatomy
- Figure with poster stage
- Native activation button
- Caption and durable fallback link
- Optional authored transcript
Variants and sizes
- 16:9 default — shown above
- Authored ratio via --thin-video-ratio — shown above
- Captioned — shown above
- Transcript included — shown above
States and difficult content
Rendered fixtures exercise authored content and constrained layouts with the same production assets.
Poster, loading and loaded player
Play creates the iframe and exposes a loading marker until its document loads. Ready means the iframe document loaded, not that media playback succeeded. HTTP/player failures cannot reliably be inferred from iframe load/error events, so the direct link remains available. Inspect this constrained fixture at different widths.
<section style="max-inline-size: 18rem">
<figure class="thin-video-embed" data-video-src="/examples/video-player/" data-video-title="Moving square clip" style="--thin-video-ratio: 16 / 9; overflow-wrap: anywhere">
<div data-video-stage>
<svg viewBox="0 0 640 360" aria-hidden="true" style="inline-size: 100%; block-size: 100%">
<rect width="640" height="360" fill="#24415c"/>
<circle cx="320" cy="180" r="80" fill="#416c89"/>
</svg>
<button type="button" data-video-activate aria-label="Play moving square clip">
<svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true">
<path fill="currentColor" d="M6 3 21 12 6 21Z"/>
</svg>
</button>
</div>
<figcaption>Moving square clip. <a href="/examples/video-player/">Open the captioned player directly</a>. The local sample has no audio.</figcaption>
<details>
<summary>Transcript and visual description</summary>
<p>A light blue square moves from left to right across a dark blue background. There is no audio.</p>
</details>
</figure>
<script type="module">
import { enhanceVideoEmbeds } from "/behaviors.js";
enhanceVideoEmbeds(document);
</script>
</section>Show code
<section style="max-inline-size: 18rem">
<figure class="thin-video-embed" data-video-src="/examples/video-player/" data-video-title="Moving square clip" style="--thin-video-ratio: 16 / 9; overflow-wrap: anywhere">
<div data-video-stage>
<svg viewBox="0 0 640 360" aria-hidden="true" style="inline-size: 100%; block-size: 100%">
<rect width="640" height="360" fill="#24415c"/>
<circle cx="320" cy="180" r="80" fill="#416c89"/>
</svg>
<button type="button" data-video-activate aria-label="Play moving square clip">
<svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="true">
<path fill="currentColor" d="M6 3 21 12 6 21Z"/>
</svg>
</button>
</div>
<figcaption>Moving square clip. <a href="/examples/video-player/">Open the captioned player directly</a>. The local sample has no audio.</figcaption>
<details>
<summary>Transcript and visual description</summary>
<p>A light blue square moves from left to right across a dark blue background. There is no audio.</p>
</details>
</figure>
<script type="module">
import { enhanceVideoEmbeds } from "/behaviors.js";
enhanceVideoEmbeds(document);
</script>
</section>Server-authored unavailable player
A static failed-state response keeps a readable error, transcript and direct player link. It does not pretend that browsers expose every third-party HTTP failure to the embedding page.
Show code
<figure class="thin-video-embed" data-video-src="/examples/video-player/" data-video-title="Moving square clip" style="--thin-video-ratio: 16 / 9; overflow-wrap: anywhere">
<div data-video-stage>
<svg viewBox="0 0 640 360" aria-hidden="true" style="inline-size: 100%; block-size: 100%">
<rect width="640" height="360" fill="#24415c"/>
<circle cx="320" cy="180" r="80" fill="#416c89"/>
</svg>
</div>
<figcaption>Moving square clip. <a href="/examples/video-player/">Open the captioned player directly</a>. The local sample has no audio.</figcaption>
<p role="alert" data-video-status>The embedded player is unavailable. Use the direct player link.</p>
<details>
<summary>Transcript and visual description</summary>
<p>A light blue square moves from left to right across a dark blue background. There is no audio.</p>
</details>
</figure>
<script type="module">
import { enhanceVideoEmbeds } from "/behaviors.js";
enhanceVideoEmbeds(document);
</script>- Poster — shown above
- Loading after consent — shown above
- Ready — shown above
- Failed with fallback link — shown above
- Narrow container — shown above
Interaction and keyboard behavior
A native button creates the iframe on click; Enter and Space activation are supplied by the browser. The authored link remains independently usable.
Accessibility
Give the activation button and created iframe a specific accessible name. Provide captions in the chosen player and an adjacent transcript when appropriate; never rely on the poster to convey essential information.
- Contract
MEDIA- Basis
- Native media or a native link fallback; no custom media role
- Evidence
tests/unit/behaviors/video-embed.test.ts
API
Use .thin-video-embed with data-video-src and data-video-title. The optional data-video-allow, data-video-sandbox, and data-video-allowfullscreen attributes are copied to the iframe only after activation.
Behavior tier: dependency-free
Custom properties
--thin-video-ratio16 / 9Aspect ratio of the poster and activated iframe stage.Fallback
Without JavaScript, the poster, description, transcript, and ordinary platform-independent watch link remain available; no iframe or provider request is created.
Assets and dependencies
/components.css/behaviors.js
Dependencies: None
Source: packages/ui/src/items/video-embed/style.ts