Skins
Packaged player designs that combine UI components and styles for specific use cases
Skins are complete, packaged player designs that include both UI components and their styles. Pick a skin that matches your use case, or eject one in your framework of choice and make it your own.
Skins in v10+
In Video.js v8, skins were CSS-only themes applied to a fixed component structure. In v10+, skins are fundamentally different:
| v8 Skins | v10+ Skins |
|---|---|
| CSS-only themes | UI components + styles packaged together |
| Fixed component structure | Each skin defines its own components |
| Limited customization | Fully customizable via eject |
This means each skin can be completely unique—different layouts, different controls, different interactions. A streaming app skin can have a totally different structure than a news player skin.
Skins and Use Cases
Video.js v10+ is built around use cases —common scenarios like website players, background video, news embeds, or streaming apps. Each use case defines a preset (the features needed) and pairs with specific skins designed for that scenario.
Skins are tied to use cases. A skin is designed for a specific feature set. If you use a website skin with a news player (which includes ads), the website skin won’t suddenly show ads UI—it simply doesn’t include those components. The skin defines what UI exists; the player defines what features are available.
| Player | Available Skins |
|---|---|
<website-video-player> | <website-frosted-video-skin>, <website-minimal-video-skin> |
<background-video-player> | (no UI) |
<news-video-player> | <news-video-skin> |
<streaming-app-video-player> | <streaming-app-video-skin> |
Skins are standalone custom elements . The element name includes the use case, style, and media type: website-frosted-video-skin. This groups related skins in IDE autocomplete and makes the purpose clear.
| Preset | Available Skins |
|---|---|
presets.website() | <FrostedSkin>, <MinimalSkin> |
presets.background() | (no UI) |
presets.news() | <NewsSkin> |
presets.streamingApp() | <StreamingSkin> |
Skins are React components that you import and compose. The component name reflects the style.
The website use case intentionally offers multiple skins. Frosted is opinionated and recognizable; Minimal is clean and easy to customize. Most other use cases have a sensible default.
Built-in Skins
Frosted
A modern, glassy design with backdrop blur effects and polished interactions.
import { createPlayer, presets, FrostedSkin, Video } from '@videojs/react';
import '@videojs/react/skins/frosted.css';
const { Provider } = createPlayer(presets.website());
<Provider>
<FrostedSkin>
<Video src="video.mp4" />
</FrostedSkin>
</Provider><website-video-player>
<website-frosted-video-skin>
<video src="video.mp4"></video>
</website-frosted-video-skin>
</website-video-player>Minimal
A clean, straightforward design that focuses on simplicity. A good starting point for customization.
import { createPlayer, presets, MinimalSkin, Video } from '@videojs/react';
import '@videojs/react/skins/minimal.css';
const { Provider } = createPlayer(presets.website());
<Provider>
<MinimalSkin>
<Video src="video.mp4" />
</MinimalSkin>
</Provider><website-video-player>
<website-minimal-video-skin>
<video src="video.mp4"></video>
</website-minimal-video-skin>
</website-video-player>Customizing Skins
Eject and Modify
Instead of overriding styles from the outside, eject a skin into your project. This copies all the components and styles in your framework of choice, giving you full control. Inspired by shadcn/ui and Create React App’s eject .
A CLI for ejecting skins is coming soon. For now, you can manually copy a skin’s components and styles from its documentation page.
Copy a skin into your project →Build from Scratch
A skin is a component that:
- Wraps content in a
MediaContainer - Accepts
children(for the media element) - Arranges UI components from the
media-*namespace - Provides styles
- Wraps content in a
media-container - Includes a
<slot>(for the media element) - Arranges UI components from the
media-*namespace - Provides styles
import { MediaContainer, PlayButton, TimeSlider } from '@videojs/react';
export function CustomSkin({ children, className }) {
return (
<MediaContainer className={className}>
{children}
<div className="controls">
<PlayButton />
<TimeSlider.Root>
<TimeSlider.Track>
<TimeSlider.Progress />
</TimeSlider.Track>
<TimeSlider.Thumb />
</TimeSlider.Root>
</div>
</MediaContainer>
);
}<!-- Custom skin element - UI primitives use media-* namespace -->
<media-container class="custom-skin">
<slot></slot>
<div class="controls">
<media-play-button></media-play-button>
<media-time-slider></media-time-slider>
</div>
</media-container>To register your custom skin as a custom element, follow the naming convention:
import { createSkin } from '@videojs/html';
const { SkinElement } = createSkin(/* ... */);
// {usecase}-{style}-{mediatype}-skin
SkinElement.define('website-custom-video-skin');See Also
- UI Components — The primitives skins are built from
- Presets — How use cases define features
- Architecture — Where skins fit in the three-pillar model