diff --git a/site/src/content/docs/reference/controls.mdx b/site/src/content/docs/reference/controls.mdx
index eb558426..b602c38a 100644
--- a/site/src/content/docs/reference/controls.mdx
+++ b/site/src/content/docs/reference/controls.mdx
@@ -50,6 +50,7 @@ User activity is tracked via pointer movement, keyboard input, and focus events
## Styling
By default, controls have the following styles:
+
```css
/* Click-through: clicks pass through controls to video beneath */
media-controls {
@@ -69,10 +70,41 @@ media-controls:not([data-visible]) {
opacity: 0;
}
```
+
+
+
+React renders `
` elements with the same data attributes. Add a `className` and use it as the selector:
+
+```css
+/* Click-through: clicks pass through controls to video beneath */
+.controls {
+ pointer-events: none;
+}
+
+.controls-group {
+ pointer-events: auto;
+}
+
+/* Fade transition */
+.controls {
+ transition: opacity 0.25s;
+}
+
+.controls:not([data-visible]) {
+ opacity: 0;
+}
+```
+
## Accessibility
+
No ARIA role is applied to `` — it is a layout wrapper, not a landmark. `` automatically receives `role="group"` when an `aria-label` or `aria-labelledby` attribute is provided; otherwise no role is assigned.
+
+
+
+No ARIA role is applied to `Controls.Root` — it is a layout wrapper, not a landmark. `Controls.Group` automatically receives `role="group"` when an `aria-label` or `aria-labelledby` attribute is provided; otherwise no role is assigned.
+
## Examples
diff --git a/site/src/content/docs/reference/fullscreen-button.mdx b/site/src/content/docs/reference/fullscreen-button.mdx
index cc53fc42..ac63dd62 100644
--- a/site/src/content/docs/reference/fullscreen-button.mdx
+++ b/site/src/content/docs/reference/fullscreen-button.mdx
@@ -43,20 +43,43 @@ Toggles fullscreen mode. Detects platform support through `availability` — whe
You can style the button based on fullscreen state:
+
```css
/* In fullscreen */
media-fullscreen-button[data-fullscreen] {
background: red;
}
```
+
+
+
+React renders a `
Consider hiding the button when unsupported:
+
```css
media-fullscreen-button[data-availability="unsupported"] {
display: none;
}
```
+
+
+
+```css
+.fullscreen-button[data-availability="unsupported"] {
+ display: none;
+}
+```
+
## Accessibility
diff --git a/site/src/content/docs/reference/mute-button.mdx b/site/src/content/docs/reference/mute-button.mdx
index 80b48764..512ec09d 100644
--- a/site/src/content/docs/reference/mute-button.mdx
+++ b/site/src/content/docs/reference/mute-button.mdx
@@ -54,19 +54,41 @@ Toggles mute on and off, and exposes a derived `volumeLevel` based on the curren
Style the button based on muted state:
+
```css
media-mute-button[data-muted] .icon-muted { display: inline; }
media-mute-button:not([data-muted]) .icon-unmuted { display: inline; }
```
+
+
+
+React renders a `
Use `data-volume-level` for multi-level icon switching:
+
```css
media-mute-button[data-volume-level="off"] .icon-off { display: inline; }
media-mute-button[data-volume-level="low"] .icon-low { display: inline; }
media-mute-button[data-volume-level="medium"] .icon-medium { display: inline; }
media-mute-button[data-volume-level="high"] .icon-high { display: inline; }
```
+
+
+
+```css
+.mute-button[data-volume-level="off"] .icon-off { display: inline; }
+.mute-button[data-volume-level="low"] .icon-low { display: inline; }
+.mute-button[data-volume-level="medium"] .icon-medium { display: inline; }
+.mute-button[data-volume-level="high"] .icon-high { display: inline; }
+```
+
## Accessibility
diff --git a/site/src/content/docs/reference/pip-button.mdx b/site/src/content/docs/reference/pip-button.mdx
index f3637b1e..70da4b14 100644
--- a/site/src/content/docs/reference/pip-button.mdx
+++ b/site/src/content/docs/reference/pip-button.mdx
@@ -43,20 +43,43 @@ Toggles picture-in-picture (PiP) mode. Detects platform support through `availab
You can style the button based on PiP state:
+
```css
/* In PiP mode */
media-pip-button[data-pip] {
background: red;
}
```
+
+
+
+React renders a `
Consider hiding the button when unsupported:
+
```css
media-pip-button[data-availability="unsupported"] {
display: none;
}
```
+
+
+
+```css
+.pip-button[data-availability="unsupported"] {
+ display: none;
+}
+```
+
## Accessibility
diff --git a/site/src/content/docs/reference/play-button.mdx b/site/src/content/docs/reference/play-button.mdx
index 2ae725fa..88a4d9d9 100644
--- a/site/src/content/docs/reference/play-button.mdx
+++ b/site/src/content/docs/reference/play-button.mdx
@@ -43,6 +43,7 @@ PlayButton is a three-state button: **play**, **pause**, and **replay**. When me
Style with the `[data-paused]` and `[data-ended]` attributes to show/hide play/pause/replay icons based on state. For example:
+
```css
/* Paused (but not ended) */
media-play-button[data-paused]:not([data-ended]) .play-icon { display: inline; }
@@ -53,13 +54,38 @@ media-play-button:not([data-paused]) .pause-icon { display: inline; }
/* Ended */
media-play-button[data-ended] .replay-icon { display: inline; }
```
+
+
+
+React renders a `
After first play, the `data-started` attribute is added and remains present until a new source is loaded. Use this to hide the play button when media hasn't started yet:
+
```css
/* Hide play button before first play */
media-play-button:not([data-started]) .play-icon { display: none; }
```
+
+
+
+```css
+/* Hide play button before first play */
+.play-button:not([data-started]) .play-icon { display: none; }
+```
+
## Accessibility
diff --git a/site/src/content/docs/reference/popover.mdx b/site/src/content/docs/reference/popover.mdx
index 9b8d626a..756ffd7e 100644
--- a/site/src/content/docs/reference/popover.mdx
+++ b/site/src/content/docs/reference/popover.mdx
@@ -68,15 +68,29 @@ The `side` and `align` props control popup placement relative to the trigger. Th
Use [CSS custom properties](#root-css-custom-properties) for positioning offsets:
+
```css
media-popover {
--media-popover-side-offset: 8px;
--media-popover-align-offset: 0px;
}
```
+
+
+
+React renders standard DOM elements with the same data attributes and CSS custom properties. Add a `className` and use it as the selector:
+
+```css
+.popover {
+ --media-popover-side-offset: 8px;
+ --media-popover-align-offset: 0px;
+}
+```
+
Style based on open state and transition phases:
+
```css
media-popover[data-open] .popup {
display: block;
@@ -88,6 +102,21 @@ media-popover[data-ending-style] .popup {
opacity: 0;
}
```
+
+
+
+```css
+.popover[data-open] .popup {
+ display: block;
+}
+.popover[data-starting-style] .popup {
+ opacity: 0;
+}
+.popover[data-ending-style] .popup {
+ opacity: 0;
+}
+```
+
## Accessibility
diff --git a/site/src/content/docs/reference/poster.mdx b/site/src/content/docs/reference/poster.mdx
index 82b03f24..1f7ddaf6 100644
--- a/site/src/content/docs/reference/poster.mdx
+++ b/site/src/content/docs/reference/poster.mdx
@@ -47,11 +47,23 @@ The poster is visible before playback starts. Once the user plays or seeks, the
Style the poster with the `[data-visible]` attribute:
+
```css
media-poster:not([data-visible]) {
display: none;
}
```
+
+
+
+React renders an `` with the same data attributes. Add a `className` and use it as the selector:
+
+```css
+.poster:not([data-visible]) {
+ display: none;
+}
+```
+
You control the child `` — this means `srcset`, `sizes`, `loading="lazy"`, and framework image components all work naturally.
diff --git a/site/src/content/docs/reference/thumbnail.mdx b/site/src/content/docs/reference/thumbnail.mdx
index 9a64d486..f066d49e 100644
--- a/site/src/content/docs/reference/thumbnail.mdx
+++ b/site/src/content/docs/reference/thumbnail.mdx
@@ -99,6 +99,7 @@ The component picks the latest thumbnail whose `startTime` is less than or equal
Use state data attributes for pure CSS styling:
+
```css
media-thumbnail[data-hidden] {
display: none;
@@ -112,6 +113,25 @@ media-thumbnail[data-error] {
outline: 1px solid #ef4444;
}
```
+
+
+
+React renders a `
` with the same data attributes. Add a `className` and use it as the selector:
+
+```css
+.thumbnail[data-hidden] {
+ display: none;
+}
+
+.thumbnail[data-loading] {
+ opacity: 0.6;
+}
+
+.thumbnail[data-error] {
+ outline: 1px solid #ef4444;
+}
+```
+
## Accessibility
diff --git a/site/src/content/docs/reference/time-slider.mdx b/site/src/content/docs/reference/time-slider.mdx
index a6230253..fb2d7dd5 100644
--- a/site/src/content/docs/reference/time-slider.mdx
+++ b/site/src/content/docs/reference/time-slider.mdx
@@ -45,19 +45,41 @@ Seeking is throttled via the `commitThrottle` prop (default 100ms) to avoid over
Use [CSS custom properties](#root-css-custom-properties) to style the fill, pointer, and buffer levels:
+
```css
media-time-slider::before {
width: calc(var(--media-slider-fill) * 1%);
}
```
+
+
+
+React renders a `
` with the same data attributes and CSS custom properties. Add a `className` and use it as the selector:
+
+```css
+.time-slider::before {
+ width: calc(var(--media-slider-fill) * 1%);
+}
+```
+
Use `data-seeking` to style during active seek operations:
+
```css
media-time-slider[data-seeking] {
opacity: 0.8;
}
```
+
+
+
+```css
+.time-slider[data-seeking] {
+ opacity: 0.8;
+}
+```
+
## Accessibility
diff --git a/site/src/content/docs/reference/volume-slider.mdx b/site/src/content/docs/reference/volume-slider.mdx
index 6afe2658..5c165696 100644
--- a/site/src/content/docs/reference/volume-slider.mdx
+++ b/site/src/content/docs/reference/volume-slider.mdx
@@ -43,11 +43,23 @@ Controls the media volume level. The slider maps its 0–100 internal range to t
Use [CSS custom properties](#root-css-custom-properties) to style the fill and pointer levels:
+
```css
media-volume-slider::before {
width: calc(var(--media-slider-fill) * 1%);
}
```
+
+
+
+React renders a `
` with the same data attributes and CSS custom properties. Add a `className` and use it as the selector:
+
+```css
+.volume-slider::before {
+ width: calc(var(--media-slider-fill) * 1%);
+}
+```
+
## Accessibility