Customize Quickplay Player
This guide covers UI customization for QuickplayPlayer and ContentPlayer.
You can tune controls, error overlay behavior, viewport behavior, top and
middle chrome content, and CSS variables without modifying bundled player
code.
Choose a theme
Use the theme prop to switch between the built-in visual themes without
writing custom CSS. It's the fastest way to change the player's overall look
before reaching for CSS custom properties.
<QuickplayPlayer source={source} theme="sutro" />
theme accepts 'sutro' or 'quickplay' (the default). See
API reference for the full prop signature.
Configure controls options
Use controlsOptions to toggle optional controls and customize built-in error
overlay copy and actions. Audio track selection, video quality, playback speed,
and caption menus are built in and appear automatically when the stream
supports them — no extra configuration is needed.
<QuickplayPlayer
source={source}
controlsOptions={{
showPipButton: true,
showCastButton: true,
showCaptionsButton: true,
showErrorOverlay: true,
errorTitle: 'Something went wrong',
errorMessage: "We couldn't play this video",
errorPrimaryLabel: 'Try again',
errorSecondaryLabel: 'Go back',
onErrorPrimary: () => window.location.reload(),
onErrorSecondary: () => window.history.back(),
}}
/>
controlsOptions supports these fields:
| Field | Type | Default | Description |
|---|---|---|---|
showPipButton | boolean | false | Show the Picture-in-Picture button. |
showCastButton | boolean | false | Show the Chromecast button. |
showCaptionsButton | boolean | false | Show an inline captions toggle in addition to the captions menu. |
showErrorOverlay | boolean | true | Show the built-in error overlay on playback failure. |
errorTitle | string | — | Heading text for the error overlay. |
errorMessage | string | — | Body text for the error overlay. |
errorPrimaryLabel | string | — | Primary action button label. |
errorSecondaryLabel | string | — | Secondary action button label. |
onErrorPrimary | () => void | — | Callback for the primary error action button. |
onErrorSecondary | () => void | — | Callback for the secondary error action button. |
Configure viewport behavior
Use viewportOptions to control how the player reacts as it scrolls in and
out of the viewport. These options let you pause offscreen playback, shrink
the player into a floating picture-in-picture window, or require a click
before playback starts. The IntersectionObserver tuning fields let you adjust
exactly when the player is considered "in view."
viewportOptions supports these behavior flags:
| Field | Type | Default | Description |
|---|---|---|---|
pauseWhenOffscreen | boolean | false | Pause playback automatically when the player scrolls out of view, and resume it when the player scrolls back into view. Has no effect while enableFloatingPip keeps the player visible in a floating window. |
enableFloatingPip | boolean | false | Shrink the player into a floating picture-in-picture window when it scrolls out of view, instead of pausing it. Takes priority over pauseWhenOffscreen when both are enabled. |
requireClickToPlay | boolean | false | Require the viewer to click the player before playback starts, even if autoplay is otherwise enabled. Overrides autoplay behavior that would otherwise trigger when the player enters the viewport. |
viewportOptions also accepts these IntersectionObserver tuning fields:
| Field | Type | Default | Description |
|---|---|---|---|
root | Element | null | null | The scrollable ancestor element used to calculate visibility. Defaults to the browser viewport when null. |
rootMargin | string | '0px' | Margin around root that grows or shrinks the area considered "in view" before visibility changes trigger. Accepts CSS margin syntax, for example '100px 0px'. |
threshold | number | 0 | The percentage of the player, expressed as a number between 0 and 1, that must be visible before it's considered in view. Higher values delay when pauseWhenOffscreen and enableFloatingPip take effect. |
Replace the default top chrome
You can supply custom top overlay content through the top-chrome slot.
<QuickplayPlayer source={source}>
<div slot="top-chrome" className="custom-header">
<img src="/logo.png" alt="Company logo" />
<div>
<h1>Custom title</h1>
<p>Custom metadata</p>
</div>
</div>
</QuickplayPlayer>
Add middle chrome content
You can supply custom overlay content positioned over the center of the
player through the middle-chrome slot. Use it for content like a
call-to-action overlay or a custom replay treatment that sits above the
video.
<QuickplayPlayer source={source}>
<div slot="middle-chrome" className="custom-middle">
<button onClick={handleReplay}>Watch again</button>
</div>
</QuickplayPlayer>
Apply CSS custom properties
The player exposes CSS custom properties so you can brand controls without
touching bundled CSS. Set overrides on media-controller to apply to every
player on the page, or combine with className to target a specific instance.
/* All players */
media-controller {
--media-accent-color: #f97316;
--media-menu-background: #1a1a2e;
}
<QuickplayPlayer source={source} className="brand-player" />
/* One specific player */
media-controller.brand-player {
--media-accent-color: #00b4d8;
--media-primary-color: #f0f0f0;
}
Try it: set your brand's accent color
Edit the hex values below to see the player's progress bar, seek thumb, and
menu checkmarks update immediately — no CSS file or rebuild required for
this preview. In your app, set the same custom properties from a CSS file
or a style attribute, as shown above.
function BrandColorExample() { const source = { contentUrl: 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8', drmLicenseUrl: '', mediaType: 'hls', drmScheme: 'none', }; // Try changing these hex values. The `.brand-color-demo` class combined // with `className` gives the override enough specificity to beat the // theme's own defaults, which are set directly on the same element. const accentColor = '#f97316'; const menuBackground = '#1a1a2e'; return ( <> <style>{` .brand-color-demo.qp-theme--quickplay { --media-accent-color: ${accentColor}; --media-menu-background: ${menuBackground}; } `}</style> <ContentPlayer source={source} title="Brand color demo" className="brand-color-demo w-full h-full" controls autoPlay // Browsers only allow autoplay when muted. Unmute anytime from // the volume control. muted /> </> ); }
Colors
| Property | Default | Description |
|---|---|---|
--media-primary-color | #ffffff | Icon and text fill. |
--media-secondary-color | transparent | Control bar background tint. |
--media-accent-color | #0778D6 | Progress bar fill, range thumb, and menu checkmark. |
--media-menu-background | #252732 | Background for overlay menus (audio, quality, etc.). |
--media-tooltip-background | #252732 | Tooltip background. |
--media-tooltip-text-color | #ffffff | Tooltip text color. |
--media-live-button-indicator-color | #E42121 | Live indicator dot. |
Seek bar
| Property | Default | Description |
|---|---|---|
--media-range-track-background | rgba(255, 255, 255, 0.5) | Track color. |
--media-range-track-pointer-background | rgba(255, 255, 255, 0.5) | Hover-preview pointer color. |
--media-time-range-buffered-color | rgba(255, 255, 255, 0.5) | Buffered portion color. |
Volume slider
| Property | Default | Description |
|---|---|---|
--media-range-track-background | rgba(255, 255, 255, 0.2) | Track color. |
--media-range-thumb-background | #ffffff | Thumb color. |
Typography and sizing
| Property | Default | Description |
|---|---|---|
--media-font-family | Roboto, sans-serif | Font family. |
--media-text-color | same as --media-primary-color | Main text color. |
--media-control-hover-background | transparent | Control hover state. |
--media-range-track-height | 4px | Seek and volume track height. |
--media-range-thumb-height | 16px | Range thumb height. |
--media-range-thumb-width | 16px | Range thumb width. |
--media-range-thumb-border-radius | 50% | Range thumb corner radius. |
--media-tooltip-border-radius | 4px | Tooltip corner radius. |
--media-tooltip-padding | 5px 10px | Tooltip padding. |
--media-tooltip-font-size | 12px | Tooltip font size. |
Scale all controls
--base (default 18px) scales control heights, icon sizes, and font sizes
together. Use it for compact or large-format players:
media-controller {
--base: 14px; /* smaller controls */
}
Target individual controls
For finer control, target media-chrome elements directly under
media-controller.
Note: Targeting individual controls directly is not part of the stable public API and may break across minor releases. Prefer CSS custom properties where possible.
media-controller media-play-button {
width: 48px;
height: 48px;
}
media-controller media-fullscreen-button {
display: none;
}
Next steps
Continue with feature-specific behavior and diagnostics.
- Add advanced playback options in Advanced usage
- Validate prop compatibility in API reference