youtube-player
Privacy-first YouTube embed with facade pattern. Zero iframe bytes until click — renders a thumbnail and play button, then swaps to the real player on interaction.
Overview
A lightweight YouTube embed that uses the facade pattern — renders a thumbnail image with a play button on page load, deferring the ~500 KB YouTube iframe until the user actually clicks play. Uses youtube-nocookie.com for privacy: no cookies are set until the user initiates playback.
Light DOM only (no shadow root), so design tokens and utility classes apply naturally.
Default
Provide a YouTube video ID via video-id and an accessible title via title.
Rounded
Apply the rounded class (inherited from the <video> native element vocabulary).
With Caption
Wrap in a <figure> with <figcaption> for a captioned embed.
Playlist
Pass a YouTube playlist ID via list. YouTube manages the playlist UI inside the iframe.
Start at Timestamp
Use start to begin playback at a specific second.
Attributes
| Attribute | Required | Type | Default | Description |
|---|---|---|---|---|
video-id | Yes | string | — | YouTube video ID |
title | Recommended | string | "Play video" | Accessible title for iframe and play button |
start | — | integer | — | Start playback at N seconds |
list | — | string | — | YouTube playlist ID |
params | — | string | — | Raw query string appended to embed URL (escape hatch) |
autoplay | — | boolean | false | Skip facade — load iframe immediately |
thumbnail | — | string | hq | Thumbnail resolution: hq, mq, sd, maxres |
Component-Managed Attributes
| Attribute | Values | Description |
|---|---|---|
state | ready, active | Facade showing vs iframe loaded |
CSS Classes
Inherited from the <video> native element vocabulary — no new classes invented.
| Class | Effect |
|---|---|
widescreen | 16:9 aspect ratio (default) |
standard | 4:3 aspect ratio |
ultrawide | 21:9 aspect ratio |
rounded | Border radius via --radius-m token |
full | inline-size: 100% |
Progressive Enhancement
Author an <a> fallback inside the element. Without JavaScript, the link takes the user to YouTube. Once the component upgrades, the facade replaces the link.
| Scenario | Behaviour |
|---|---|
| No JS | Anchor link to YouTube visible |
| JS loaded | Facade: thumbnail + play button |
| User clicks | Iframe replaces facade, video autoplays |
autoplay | Iframe rendered immediately — no facade step |
Accessibility
- Thumbnail image has
alt=""(decorative — the button has the label) - Play button has
aria-label="Play {title}" - Host element gets
tabindex="0"androle="button"in facade state for keyboard access - Enter and Space activate the embed
- After activation, focus moves to the iframe
- Iframe has a descriptive
titleattribute - No-JS fallback is a plain anchor with meaningful text
- No animations that violate
prefers-reduced-motion
Performance
| Metric | Value |
|---|---|
| JS size | < 2 KB |
| CSS size | < 1 KB |
| Network requests before click | 1 (thumbnail image only) |
| YouTube cookies before click | None (youtube-nocookie.com) |
Related
<video-player>— Self-hosted video with custom overlay controls<video>— Native video element (aspect-ratio classes shared with this component)<iframe>— Native iframe element