GuideGetting Started
Build your own skin
Create a skin project, preview it locally, and compose your own player interface from Video.js UI components
A skin is the player interface: markup that arranges Video.js UI components inside the player, plus the styles that give it a look. The components handle playback state, keyboard support, and accessibility, so building your own skin is mostly a layout and design job. Skins explains how skins fit into Video.js.
If a packaged skin is already close to what you want, Customize skins is less work.
Create a skin project
The quickest way to start is a standalone skin project:
The command asks for a name, a framework (React or HTML), a styling approach (Tailwind or CSS), a starting skin, and a preset (video, audio, live video, or live audio). The starting skin defaults to Scaffold: every control wired up, with minimal styling and no transitions, so there’s little to undo.
The project goes in a folder named after the skin, so a skin called “My Skin” goes in my-skin. Open it and start the preview:
The project has two parts:
src/holds the skin and nothing else. Edit it however you like, including its markup, class names, theme tokens, and stylesheets.apps/preview/is a workbench that plays your skin. Use it to try different player sizes and aspect ratios, light and dark color schemes, right-to-left text, every built-in language, and playback settings such as autoplay and loop.
When you want to share it, deploy the workbench to Vercel, Netlify, or Cloudflare Pages:
Add the host’s name to skip the question, as in npm run deploy vercel. With pnpm, keep the run, since pnpm deploy is a built-in pnpm command. When the skin is done, move src/ into your app.
Build it with a coding agent
If you work with a coding agent, such as Claude Code, Codex, or Cursor, it can do all of this for you. Install the Video.js skills, which include a skill for building skins:
Then ask your agent something like “Help me design my own Video.js skin for our podcast player.” It asks for the same choices as the command, creates the project, starts the workbench, and agrees a design with you before styling. It can also match an existing player’s look from a screenshot or a link, then checks its work against the reference and for accessibility before handing back. Build with AI covers installing the skills in each agent.
Other starting points
- Inside an existing app. Add a skin’s source with Install with Shadcn and pick Scaffold as the skin.
- From nothing. Put a Container inside your player and add the components you want, as in the example below.
No path requires Scaffold’s structure, its theme tokens, or any particular CSS approach.
A minimal skin
This example shows how a skin fits together without Scaffold’s extra parts. It has a play button, a timeline, the current time, mute, fullscreen, keyboard shortcuts, screen reader announcements, and an error dialog. The player provides state, the Container is the skin’s root, and the media element goes inside the Container next to the controls.
Use it the same way as a packaged skin, with the media as its child:
videoFeatures gives the player the state these controls need. Some controls, such as Cast or Quality, depend on features that not every preset includes. Each control’s reference page names the feature it needs.
This CSS places the controls over the video, hides them when the viewer is idle, draws the timeline, and keeps the error dialog hidden until playback fails:
From here, add the components your design needs.
Pick the components
Each skin is made of the same building blocks. Use the ones your design needs; their reference pages cover props, state, data attributes, and examples.
Some of these are easy to leave out by accident because they have little or no visible UI. Include the error dialog, keyboard shortcuts, and status announcer unless you replace them with your own.
To build a control Video.js doesn’t provide, follow Build your own UI component.
Style it your way
The components bring no visual styles. You add the icons, text, and CSS. They describe their state with data-* attributes, such as data-paused on the play button, so you can style them with plain CSS, Tailwind, or anything else. UI components explains how. Automatically show and hide controls covers the controls’ visibility states.
Lay out controls in source order that matches their visual order, so keyboard focus follows the layout.
A player’s controls sit over a moving picture, in a frame whose size you don’t control, so a few design questions come up in every skin:
- Surfaces over video. Borders, shadows, and translucent backgrounds look different over every frame. Shapes and surfaces and Letting the content influence the color cover how our skins handle them.
- Readable controls. Seek tracks need a visible target, icons need optical alignment, and time displays need fixed-width digits. See Controls and typography.
- Motion. Menus should open from the control that opened them and respond when they’re closed mid-transition. See Motion and transitions.
- Small players. Captions, settings, picture-in-picture, and Cast all compete for space at narrow widths. See Fitting the available space.
- Custom colors. An accent color someone else picks still needs contrast against its text and the video. See Customization and contrast.
Design inspiration behind the Video.js v10 skins covers the thinking behind our own skins in full.
Support the public CSS properties
If the skin is only for your own site, you can skip this.
If you want to offer it as a Video.js skin, support the same CSS custom properties as the packaged skins, such as --media-accent-color and --media-border-radius. People can then restyle your skin the same way they restyle ours. Set the skin’s styles lists them. We’re still working out how to accept community skins into Video.js.
Test it
Check the finished skin with real media, at the narrowest player size you support:
- Play, pause, seek, change volume, open every menu, and enter fullscreen.
- Use only a keyboard, then only touch. Focus stays visible and follows the layout, and controls hide when idle.
- Check loading, errors, ended playback, captions, and controls the browser doesn’t support.
- Check text and icon contrast over bright and dark footage, with forced colors, and with reduced motion.
Accessibility covers these checks in more detail.
Related pages
Guides
- SkinsPackaged player designs that include both UI components and their styles.
- Customize skinsStyle a packaged Video.js skin or add its source to change controls, layout, styles, and interactions
- Build your own UI componentCreate custom player controls that read state, dispatch actions, and stay accessible.