# Video.js v10 — HTML Guides (complete)
> Every HTML guides page in one file (about 133k tokens). Index with descriptions: https://videojs.org/docs/framework/html/guides/llms.txt
---
# HTML Installation Guide
Install Video.js with HTML custom elements and build an accessible, customizable video player
Video.js is an **HTML video player built on custom elements**: lightweight, framework-free components for building accessible, customizable players with minimal bundle sizes, advanced features, and consistency across browsers.
> **Tip: Coming from another player?**
>
> Follow the migration guide for [Video.js 8](https://videojs.org/docs/framework/html/guides/migrate-from-video-js-8), [Mux Player](https://videojs.org/docs/framework/html/guides/migrate-from-mux-player), [Plyr](https://videojs.org/docs/framework/html/guides/migrate-from-plyr), [Media Chrome](https://videojs.org/docs/framework/html/guides/migrate-from-media-chrome), or [Vidstack](https://videojs.org/docs/framework/html/guides/migrate-from-vidstack). Each maps your existing setup onto Video.js v10 instead of starting from scratch.
## AI Quickstart
Paste this prompt into your coding agent:
```
Install the Video.js skill: run `npx @videojs/cli agents skills` and follow the steps for the agent you are running in. If you can't run commands, follow the install instructions at https://github.com/videojs/skills instead. Then use the Video.js skill when you work on video or audio in this project. When installation details are needed, run `npx @videojs/cli agents init --framework html` to print the version-matched choices and instructions without changing files.
```
## Installation options for coding agents
The web Markdown page contains the default installation. Add the query parameters below to its `.md` URL for a complete, validated variation. From a project or an offline docs bundle, run the CLI command below instead. Both paths use the same installation renderer and only return instructions; they do not modify a project.
This page fixes the installation method to `packaged` and the framework to `html`.
```sh
npx @videojs/cli agents init
```
### Query parameters
- `project`: Whether to adapt the current project or scaffold a new one. New projects need a named app setup. Values: `new`, `existing`. Default: existing.
- `preset`: The player configuration and control set. Values: `video`, `audio`, `live-video`, `live-audio`, `background-video`. Default: video.
- `skin`: The visual skin. Neutral has cleaner surfaces and the same controls as Default. Values: `default`, `neutral`, `compat`, `none`. Default: default. Applies when preset is not background-video.
- `media`: The media source or playback adapter. See the preset compatibility map below. Values: `background-video`, `hls-background-video`, `cloudflare`, `dash`, `hls`, `html5-audio`, `html5-video`, `mux-audio`, `mux-background-video`, `mux-video`, `spotify`, `tiktok`, `twitch`, `vimeo`, `youtube`. Default: the selected preset's first compatible media source.
- `extensions`: A comma-separated list of optional player extensions compatible with the selected player. Pass `none` when no extension is needed. Values: `none`, `google-cast`, `mux-data`. Default: mux-data for Mux media; none otherwise (reported as defaulted).
- `source-url`: The http:// or https:// media URL placed in the generated player example. Pass `demo` to choose the Video.js demo source for the selected media explicitly. Default: the Video.js demo source for the selected media (reported as defaulted).
- `package-manager`: The command runner used for app setup, packages, Shadcn, and the development server. Values: `npm`, `pnpm`, `yarn`, `bun`. Default: pnpm. Applies when method is not cdn with template none.
- `template`: The app setup and file layout. Packaged `none` needs an existing bundler; use CDN for a site without a build step. Values: `vite`, `astro`, `laravel`, `none`. Default: vite.
Run the command above without flags to see the corresponding CLI flags for every framework.
### Decide in this order
1. **Inspect the project.** Read package.json, framework config, and lockfiles to infer the framework, app setup, and package manager. React installs @videojs/react; HTML, Vue, and Svelte install @videojs/html.
2. **Choose the starting point.** Use existing when adapting a compatible project. Use new only when the user wants a new app or the intended workspace has no app. Confirm the choice when the workspace and request do not make it clear.
3. **Choose the player.** Use video unless the request signals another experience: audio, music, or podcasts use audio; a live stream uses live-video or live-audio; a muted, looping decorative video uses background-video. Ask only when those signals conflict.
4. **Choose the skin.** Use default unless the request asks for a minimal, cleaner, or more subtle look, which uses neutral; both contain the same controls. Use none only when the project builds its own controls. Ask only when those signals conflict.
5. **Choose the media.** Infer the adapter from the source when possible. Mux wins for Mux playback URLs: stream.mux.com/\.m3u8 or a bare playback ID uses mux-video, mux-audio, or mux-background-video rather than hls. Mux static renditions such as .mp4 or .m4a files use html5-video or html5-audio. Other .m3u8 URLs use hls.
6. **Choose extensions.** Mux Data is included by default for Mux video and audio sources. Add Google Cast when a standard or live video player with a ready-made skin should cast a compatible source. Use none when no extension is needed.
7. **Choose how to install.** This guide uses packaged modules, which need a bundler. Match the package manager to the project lockfile. For an existing HTML site without a build step, use CDN scripts instead.
8. **Return one explicit plan.** Confirm the choices once, then pass every applicable query parameter, including `extensions=none` when no extension is needed and `source-url=demo` when there is no media URL yet. Check that Defaulted options says none. Adapt conditional setup steps and existing paths before changing files.
### Compatible media sources by preset
- `video`: `html5-video`, `hls`, `dash`, `mux-video`, `vimeo`, `youtube`, `cloudflare`, `tiktok`, `twitch`
- `audio`: `html5-audio`, `mux-audio`, `spotify`
- `live-video`: `hls`, `mux-video`
- `live-audio`: `mux-audio`
- `background-video`: `background-video`, `hls-background-video`, `mux-background-video`
### App setup by framework
- `html`: templates `vite`, `astro`, `laravel`, `none`
### Installation pages
- [Packaged modules: React](https://videojs.org/docs/guides/installation/react.md)
- [Packaged modules: HTML](https://videojs.org/docs/guides/installation/html.md)
- [Packaged modules: Vue](https://videojs.org/docs/guides/installation/vue.md)
- [Packaged modules: Svelte](https://videojs.org/docs/guides/installation/svelte.md)
- [Editable Shadcn source: React source](https://videojs.org/docs/guides/installation/shadcn.md?framework=react)
- [Editable Shadcn source: HTML source](https://videojs.org/docs/guides/installation/shadcn.md?framework=html)
- [CDN: HTML from jsDelivr](https://videojs.org/docs/guides/installation/cdn.md)
If a preset and skin do not meet your user’s requirements, follow [Customize skins](https://videojs.org/docs/framework/html/guides/customize-skins#style-skin-source) to add the files for the closest skin to the project. As you develop with Video.js, rely heavily on [llms.txt](https://videojs.org/docs/framework/html/llms.txt) to make sure you always have the latest information.
## Selected options
- `method`: `packaged`
- `framework`: `html`
- `project`: `existing`
- `preset`: `video`
- `skin`: `default`
- `media`: `html5-video`
- `extensions`: `none`
- `source-url`: `https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4`
- `package-manager`: `pnpm`
- `template`: `vite`
Defaulted options: project, preset, skin, source-url, media, extensions, template, package-manager.
## Reproduce or change these instructions
```sh
npx @videojs/cli agents init --method packaged --framework html --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --package-manager pnpm --template vite
```
## Install the packages
```bash
pnpm add @videojs/html@10.0.1
```
## Add your player
Merge the example into the existing Vite route or component that should render the player, and preserve unrelated content.
### `src/player.ts`
_Merge this into the existing file, or create the file when it is missing._
```ts
import '@videojs/html/video/player';
import '@videojs/html/video/skin';
```
### `index.html` (body)
_Merge this into the page `` where the player should appear._
```html
```
## Run your app
Start the development server and verify that the selected media plays.
_Long-running: start it in the background, verify the result, then stop it._
```bash
pnpm dev
```
> These are instructions only. Review and run the commands in your project; no files were modified.
That’s it! You now have a working Video.js player.
## Own the UI
Packaged skins keep their controls and layout inside Video.js. When you need to add, remove, rearrange, or deeply restyle controls, use Shadcn to add the skin source to your project. Its components, layout, styles, and interactions become local files you can change.
- [Install Video.js with Shadcn](https://videojs.org/docs/guides/installation/shadcn?framework=html#choose-how-to-install): Add editable skin source and build a working React or HTML player
## Choose what to do next
### Customize
- [Customize skins](https://videojs.org/docs/framework/html/guides/customize-skins#style-a-packaged-skin): Change colors, typography, sizing, and poster presentation
- [UI components](https://videojs.org/docs/framework/html/guides/architecture#ui-components): Explore the building blocks used by skins and custom controls
- [Build your own component](https://videojs.org/docs/framework/html/guides/build-your-own-component): Connect custom UI to player state and actions
### Deploy
- [Browser support](https://videojs.org/docs/framework/html/guides/browser-support): Check supported browsers and rendering environments
- [TypeScript](https://videojs.org/docs/framework/html/guides/typescript): Configure TypeScript for Video.js packages
- [Bundlers](https://videojs.org/docs/framework/html/guides/bundlers): Check bundler compatibility
- [Content Security Policy](https://videojs.org/docs/framework/html/guides/content-security-policy): Configure Content Security Policy for your player
- [CDN](https://videojs.org/docs/framework/html/guides/cdn): See every bundle the CDN serves and the layout rules behind the URLs
- [Self-host the player](https://videojs.org/docs/framework/html/guides/self-hosting): Serve the player from your own origin for offline or restricted-network deployments
Something not quite right? You can [submit an issue](https://github.com/videojs/v10/issues) and ask for help, or explore [other support options](https://videojs.org/html5-video-support).
---
# Vue Installation Guide
Install Video.js in Vue or Nuxt and build a video player with HTML custom elements
Vue apps built with Vite, Astro, or Nuxt use Video.js HTML custom elements directly in their templates. These lightweight, framework-free components build accessible, customizable players with small bundles, advanced features, and consistent behavior across browsers.
> **Tip: Coming from another player?**
>
> Follow the migration guide for [Video.js 8](https://videojs.org/docs/framework/html/guides/migrate-from-video-js-8), [Mux Player](https://videojs.org/docs/framework/html/guides/migrate-from-mux-player), [Plyr](https://videojs.org/docs/framework/html/guides/migrate-from-plyr), [Media Chrome](https://videojs.org/docs/framework/html/guides/migrate-from-media-chrome), or [Vidstack](https://videojs.org/docs/framework/html/guides/migrate-from-vidstack). Each maps your existing setup onto Video.js v10 instead of starting from scratch.
## AI Quickstart
Paste this prompt into your coding agent:
```
Install the Video.js skill: run `npx @videojs/cli agents skills` and follow the steps for the agent you are running in. If you can't run commands, follow the install instructions at https://github.com/videojs/skills instead. Then use the Video.js skill when you work on video or audio in this project. When installation details are needed, run `npx @videojs/cli agents init --framework vue` to print the version-matched choices and instructions without changing files.
```
## Installation options for coding agents
The web Markdown page contains the default installation. Add the query parameters below to its `.md` URL for a complete, validated variation. From a project or an offline docs bundle, run the CLI command below instead. Both paths use the same installation renderer and only return instructions; they do not modify a project.
This page fixes the installation method to `packaged` and the framework to `vue`.
```sh
npx @videojs/cli agents init
```
### Query parameters
- `project`: Whether to adapt the current project or scaffold a new one. New projects need a named app setup. Values: `new`, `existing`. Default: existing.
- `preset`: The player configuration and control set. Values: `video`, `audio`, `live-video`, `live-audio`, `background-video`. Default: video.
- `skin`: The visual skin. Neutral has cleaner surfaces and the same controls as Default. Values: `default`, `neutral`, `compat`, `none`. Default: default. Applies when preset is not background-video.
- `media`: The media source or playback adapter. See the preset compatibility map below. Values: `background-video`, `hls-background-video`, `cloudflare`, `dash`, `hls`, `html5-audio`, `html5-video`, `mux-audio`, `mux-background-video`, `mux-video`, `spotify`, `tiktok`, `twitch`, `vimeo`, `youtube`. Default: the selected preset's first compatible media source.
- `extensions`: A comma-separated list of optional player extensions compatible with the selected player. Pass `none` when no extension is needed. Values: `none`, `google-cast`, `mux-data`. Default: mux-data for Mux media; none otherwise (reported as defaulted).
- `source-url`: The http:// or https:// media URL placed in the generated player example. Pass `demo` to choose the Video.js demo source for the selected media explicitly. Default: the Video.js demo source for the selected media (reported as defaulted).
- `package-manager`: The command runner used for app setup, packages, Shadcn, and the development server. Values: `npm`, `pnpm`, `yarn`, `bun`. Default: pnpm. Applies when method is not cdn with template none.
- `template`: The app setup and file layout. Values: `vite`, `astro`, `nuxt`. Default: vite.
Run the command above without flags to see the corresponding CLI flags for every framework.
### Decide in this order
1. **Inspect the project.** Read package.json, framework config, and lockfiles to infer the framework, app setup, and package manager. React installs @videojs/react; HTML, Vue, and Svelte install @videojs/html.
2. **Choose the starting point.** Use existing when adapting a compatible project. Use new only when the user wants a new app or the intended workspace has no app. Confirm the choice when the workspace and request do not make it clear.
3. **Choose the player.** Use video unless the request signals another experience: audio, music, or podcasts use audio; a live stream uses live-video or live-audio; a muted, looping decorative video uses background-video. Ask only when those signals conflict.
4. **Choose the skin.** Use default unless the request asks for a minimal, cleaner, or more subtle look, which uses neutral; both contain the same controls. Use none only when the project builds its own controls. Ask only when those signals conflict.
5. **Choose the media.** Infer the adapter from the source when possible. Mux wins for Mux playback URLs: stream.mux.com/\.m3u8 or a bare playback ID uses mux-video, mux-audio, or mux-background-video rather than hls. Mux static renditions such as .mp4 or .m4a files use html5-video or html5-audio. Other .m3u8 URLs use hls.
6. **Choose extensions.** Mux Data is included by default for Mux video and audio sources. Add Google Cast when a standard or live video player with a ready-made skin should cast a compatible source. Use none when no extension is needed.
7. **Choose how to install.** This guide uses packaged modules, which need a bundler. Match the package manager to the project lockfile. For an existing HTML site without a build step, use CDN scripts instead.
8. **Return one explicit plan.** Confirm the choices once, then pass every applicable query parameter, including `extensions=none` when no extension is needed and `source-url=demo` when there is no media URL yet. Check that Defaulted options says none. Adapt conditional setup steps and existing paths before changing files.
### Compatible media sources by preset
- `video`: `html5-video`, `hls`, `dash`, `mux-video`, `vimeo`, `youtube`, `cloudflare`, `tiktok`, `twitch`
- `audio`: `html5-audio`, `mux-audio`, `spotify`
- `live-video`: `hls`, `mux-video`
- `live-audio`: `mux-audio`
- `background-video`: `background-video`, `hls-background-video`, `mux-background-video`
### App setup by framework
- `vue`: templates `vite`, `astro`, `nuxt`
### Installation pages
- [Packaged modules: React](https://videojs.org/docs/guides/installation/react.md)
- [Packaged modules: HTML](https://videojs.org/docs/guides/installation/html.md)
- [Packaged modules: Vue](https://videojs.org/docs/guides/installation/vue.md)
- [Packaged modules: Svelte](https://videojs.org/docs/guides/installation/svelte.md)
- [Editable Shadcn source: React source](https://videojs.org/docs/guides/installation/shadcn.md?framework=react)
- [Editable Shadcn source: HTML source](https://videojs.org/docs/guides/installation/shadcn.md?framework=html)
- [CDN: HTML from jsDelivr](https://videojs.org/docs/guides/installation/cdn.md)
## Selected options
- `method`: `packaged`
- `framework`: `vue`
- `project`: `existing`
- `preset`: `video`
- `skin`: `default`
- `media`: `html5-video`
- `extensions`: `none`
- `source-url`: `https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4`
- `package-manager`: `pnpm`
- `template`: `vite`
Defaulted options: project, preset, skin, source-url, media, extensions, template, package-manager.
## Reproduce or change these instructions
```sh
npx @videojs/cli agents init --method packaged --framework vue --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --package-manager pnpm --template vite
```
## Install the packages
```bash
pnpm add @videojs/html@10.0.1
```
## Register custom elements
Use the file that matches your Vue toolchain.
### `vite.config.ts`
_Merge this into the existing file, or create the file when it is missing._
```ts
import vue from '@vitejs/plugin-vue';
import { defineConfig } from 'vite';
const videoJsElements = new Set(['video-player', 'video-skin']);
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => videoJsElements.has(tag),
},
},
}),
],
});
```
## Add your player
Merge the example into the existing Vite route or component that should render the player, and preserve unrelated content.
### `src/components/VideoPlayer.vue`
_Merge this into the existing file, or create the file when it is missing._
```vue
```
### `src/App.vue`
_Merge this into the existing file, or create the file when it is missing._
```vue
```
## Run your app
Start the development server and verify that the selected media plays.
_Long-running: start it in the background, verify the result, then stop it._
```bash
pnpm dev
```
> These are instructions only. Review and run the commands in your project; no files were modified.
That’s it! You now have a working Video.js player.
> **Note: Server rendering with Nuxt**
>
> Keep the element imports static. Nuxt renders the custom-element markup on the server, and the browser upgrades it when the page loads. If you need to read player state or call player methods, wait until Vue has mounted the element. See [Use Nuxt](https://videojs.org/docs/framework/html/guides/vue#use-nuxt) for client-only registration.
## Choose what to do next
### Customize
- [Use Video.js with Vue and Nuxt](https://videojs.org/docs/framework/html/guides/vue): Read player state, pass objects as properties, and configure Nuxt
- [Customize skins](https://videojs.org/docs/framework/html/guides/customize-skins#style-a-packaged-skin): Change colors, typography, sizing, and poster presentation
- [Architecture](https://videojs.org/docs/framework/html/guides/architecture): Learn how the player, skins, media, and UI components fit together
### Deploy
- [Browser support](https://videojs.org/docs/framework/html/guides/browser-support): Check supported browsers and rendering environments
- [TypeScript](https://videojs.org/docs/framework/html/guides/typescript): Configure TypeScript for Video.js packages
- [Bundlers](https://videojs.org/docs/framework/html/guides/bundlers): Check bundler compatibility
- [Content Security Policy](https://videojs.org/docs/framework/html/guides/content-security-policy): Configure Content Security Policy for your player
- [CDN](https://videojs.org/docs/framework/html/guides/cdn): See every bundle the CDN serves and the layout rules behind the URLs
- [Self-host the player](https://videojs.org/docs/framework/html/guides/self-hosting): Serve the player from your own origin for offline or restricted-network deployments
Something not quite right? You can [submit an issue](https://github.com/videojs/v10/issues) and ask for help, or explore [other support options](https://videojs.org/html5-video-support).
---
# Svelte Installation Guide
Install Video.js in Svelte or SvelteKit and build a video player with HTML custom elements
Svelte apps built with Vite, Astro, or SvelteKit use Video.js HTML custom elements directly in their markup. These lightweight, framework-free components build accessible, customizable players with small bundles, advanced features, and consistent behavior across browsers.
> **Tip: Coming from another player?**
>
> Follow the migration guide for [Video.js 8](https://videojs.org/docs/framework/html/guides/migrate-from-video-js-8), [Mux Player](https://videojs.org/docs/framework/html/guides/migrate-from-mux-player), [Plyr](https://videojs.org/docs/framework/html/guides/migrate-from-plyr), [Media Chrome](https://videojs.org/docs/framework/html/guides/migrate-from-media-chrome), or [Vidstack](https://videojs.org/docs/framework/html/guides/migrate-from-vidstack). Each maps your existing setup onto Video.js v10 instead of starting from scratch.
## AI Quickstart
Paste this prompt into your coding agent:
```
Install the Video.js skill: run `npx @videojs/cli agents skills` and follow the steps for the agent you are running in. If you can't run commands, follow the install instructions at https://github.com/videojs/skills instead. Then use the Video.js skill when you work on video or audio in this project. When installation details are needed, run `npx @videojs/cli agents init --framework svelte` to print the version-matched choices and instructions without changing files.
```
## Installation options for coding agents
The web Markdown page contains the default installation. Add the query parameters below to its `.md` URL for a complete, validated variation. From a project or an offline docs bundle, run the CLI command below instead. Both paths use the same installation renderer and only return instructions; they do not modify a project.
This page fixes the installation method to `packaged` and the framework to `svelte`.
```sh
npx @videojs/cli agents init
```
### Query parameters
- `project`: Whether to adapt the current project or scaffold a new one. New projects need a named app setup. Values: `new`, `existing`. Default: existing.
- `preset`: The player configuration and control set. Values: `video`, `audio`, `live-video`, `live-audio`, `background-video`. Default: video.
- `skin`: The visual skin. Neutral has cleaner surfaces and the same controls as Default. Values: `default`, `neutral`, `compat`, `none`. Default: default. Applies when preset is not background-video.
- `media`: The media source or playback adapter. See the preset compatibility map below. Values: `background-video`, `hls-background-video`, `cloudflare`, `dash`, `hls`, `html5-audio`, `html5-video`, `mux-audio`, `mux-background-video`, `mux-video`, `spotify`, `tiktok`, `twitch`, `vimeo`, `youtube`. Default: the selected preset's first compatible media source.
- `extensions`: A comma-separated list of optional player extensions compatible with the selected player. Pass `none` when no extension is needed. Values: `none`, `google-cast`, `mux-data`. Default: mux-data for Mux media; none otherwise (reported as defaulted).
- `source-url`: The http:// or https:// media URL placed in the generated player example. Pass `demo` to choose the Video.js demo source for the selected media explicitly. Default: the Video.js demo source for the selected media (reported as defaulted).
- `package-manager`: The command runner used for app setup, packages, Shadcn, and the development server. Values: `npm`, `pnpm`, `yarn`, `bun`. Default: pnpm. Applies when method is not cdn with template none.
- `template`: The app setup and file layout. Values: `vite`, `astro`, `sveltekit`. Default: vite.
Run the command above without flags to see the corresponding CLI flags for every framework.
### Decide in this order
1. **Inspect the project.** Read package.json, framework config, and lockfiles to infer the framework, app setup, and package manager. React installs @videojs/react; HTML, Vue, and Svelte install @videojs/html.
2. **Choose the starting point.** Use existing when adapting a compatible project. Use new only when the user wants a new app or the intended workspace has no app. Confirm the choice when the workspace and request do not make it clear.
3. **Choose the player.** Use video unless the request signals another experience: audio, music, or podcasts use audio; a live stream uses live-video or live-audio; a muted, looping decorative video uses background-video. Ask only when those signals conflict.
4. **Choose the skin.** Use default unless the request asks for a minimal, cleaner, or more subtle look, which uses neutral; both contain the same controls. Use none only when the project builds its own controls. Ask only when those signals conflict.
5. **Choose the media.** Infer the adapter from the source when possible. Mux wins for Mux playback URLs: stream.mux.com/\.m3u8 or a bare playback ID uses mux-video, mux-audio, or mux-background-video rather than hls. Mux static renditions such as .mp4 or .m4a files use html5-video or html5-audio. Other .m3u8 URLs use hls.
6. **Choose extensions.** Mux Data is included by default for Mux video and audio sources. Add Google Cast when a standard or live video player with a ready-made skin should cast a compatible source. Use none when no extension is needed.
7. **Choose how to install.** This guide uses packaged modules, which need a bundler. Match the package manager to the project lockfile. For an existing HTML site without a build step, use CDN scripts instead.
8. **Return one explicit plan.** Confirm the choices once, then pass every applicable query parameter, including `extensions=none` when no extension is needed and `source-url=demo` when there is no media URL yet. Check that Defaulted options says none. Adapt conditional setup steps and existing paths before changing files.
### Compatible media sources by preset
- `video`: `html5-video`, `hls`, `dash`, `mux-video`, `vimeo`, `youtube`, `cloudflare`, `tiktok`, `twitch`
- `audio`: `html5-audio`, `mux-audio`, `spotify`
- `live-video`: `hls`, `mux-video`
- `live-audio`: `mux-audio`
- `background-video`: `background-video`, `hls-background-video`, `mux-background-video`
### App setup by framework
- `svelte`: templates `vite`, `astro`, `sveltekit`
### Installation pages
- [Packaged modules: React](https://videojs.org/docs/guides/installation/react.md)
- [Packaged modules: HTML](https://videojs.org/docs/guides/installation/html.md)
- [Packaged modules: Vue](https://videojs.org/docs/guides/installation/vue.md)
- [Packaged modules: Svelte](https://videojs.org/docs/guides/installation/svelte.md)
- [Editable Shadcn source: React source](https://videojs.org/docs/guides/installation/shadcn.md?framework=react)
- [Editable Shadcn source: HTML source](https://videojs.org/docs/guides/installation/shadcn.md?framework=html)
- [CDN: HTML from jsDelivr](https://videojs.org/docs/guides/installation/cdn.md)
## Selected options
- `method`: `packaged`
- `framework`: `svelte`
- `project`: `existing`
- `preset`: `video`
- `skin`: `default`
- `media`: `html5-video`
- `extensions`: `none`
- `source-url`: `https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4`
- `package-manager`: `pnpm`
- `template`: `vite`
Defaulted options: project, preset, skin, source-url, media, extensions, template, package-manager.
## Reproduce or change these instructions
```sh
npx @videojs/cli agents init --method packaged --framework svelte --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --package-manager pnpm --template vite
```
## Install the packages
```bash
pnpm add @videojs/html@10.0.1
```
## Add your player
Merge the example into the existing Vite route or component that should render the player, and preserve unrelated content.
### `src/lib/VideoPlayer.svelte`
_Merge this into the existing file, or create the file when it is missing._
```svelte
```
### `src/App.svelte`
_Merge this into the existing file, or create the file when it is missing._
```svelte
```
## Run your app
Start the development server and verify that the selected media plays.
_Long-running: start it in the background, verify the result, then stop it._
```bash
pnpm dev
```
> These are instructions only. Review and run the commands in your project; no files were modified.
That’s it! You now have a working Video.js player.
> **Note: Server rendering with SvelteKit**
>
> Keep the element imports static. SvelteKit renders the custom-element markup on the server, and the browser upgrades it when the page loads. Put code that needs the element or browser APIs in `onMount`. See [Use SvelteKit](https://videojs.org/docs/framework/html/guides/svelte#use-sveltekit) for the details.
## Choose what to do next
### Customize
- [Use Video.js with Svelte and SvelteKit](https://videojs.org/docs/framework/html/guides/svelte): Read player state in onMount, pass objects as properties, and configure SvelteKit
- [Customize skins](https://videojs.org/docs/framework/html/guides/customize-skins#style-a-packaged-skin): Change colors, typography, sizing, and poster presentation
- [Architecture](https://videojs.org/docs/framework/html/guides/architecture): Learn how the player, skins, media, and UI components fit together
### Deploy
- [Browser support](https://videojs.org/docs/framework/html/guides/browser-support): Check supported browsers and rendering environments
- [TypeScript](https://videojs.org/docs/framework/html/guides/typescript): Configure TypeScript for Video.js packages
- [Bundlers](https://videojs.org/docs/framework/html/guides/bundlers): Check bundler compatibility
- [Content Security Policy](https://videojs.org/docs/framework/html/guides/content-security-policy): Configure Content Security Policy for your player
- [CDN](https://videojs.org/docs/framework/html/guides/cdn): See every bundle the CDN serves and the layout rules behind the URLs
- [Self-host the player](https://videojs.org/docs/framework/html/guides/self-hosting): Serve the player from your own origin for offline or restricted-network deployments
Something not quite right? You can [submit an issue](https://github.com/videojs/v10/issues) and ask for help, or explore [other support options](https://videojs.org/html5-video-support).
---
# Shadcn Installation Guide
Add editable React or HTML skin source with the Shadcn registry
Use Shadcn to add a Video.js skin's components, layout, styles, and interactions as React or HTML custom-element source. The CLI copies the files into your app so you can review and change them like any other source code.
> **Tip: Coming from another player?**
>
> Follow the HTML migration guide for [Video.js 8](https://videojs.org/docs/framework/html/guides/migrate-from-video-js-8), [Mux Player](https://videojs.org/docs/framework/html/guides/migrate-from-mux-player), [Plyr](https://videojs.org/docs/framework/html/guides/migrate-from-plyr), [Media Chrome](https://videojs.org/docs/framework/html/guides/migrate-from-media-chrome), or [Vidstack](https://videojs.org/docs/framework/html/guides/migrate-from-vidstack). Each maps your existing setup onto Video.js v10 instead of starting from scratch.
## AI Quickstart
Paste this prompt into your coding agent:
```
Install the Video.js skill: run `npx @videojs/cli agents skills` and follow the steps for the agent you are running in. If you can't run commands, follow the install instructions at https://github.com/videojs/skills instead. Then use the Video.js skill when you work on video or audio in this project. When installation details are needed, run `npx @videojs/cli agents init --method shadcn --framework react` for React, or `npx @videojs/cli agents init --method shadcn --framework html` for plain HTML. The command prints version-matched choices and instructions without changing files.
```
## Installation options for coding agents
The web Markdown page contains the default installation. Add the query parameters below to its `.md` URL for a complete, validated variation. From a project or an offline docs bundle, run the CLI command below instead. Both paths use the same installation renderer and only return instructions; they do not modify a project.
This page fixes the installation method to `shadcn`. The `framework` query parameter selects React or HTML.
```sh
npx @videojs/cli agents init
```
### Query parameters
- `framework`: The application framework that will host the player. React installs @videojs/react; HTML, Vue, and Svelte install @videojs/html. Values: `react`, `html`. Default: react.
- `project`: Whether to adapt the current project or scaffold a new one. New projects need a named app setup. Values: `new`, `existing`. Default: existing.
- `preset`: The player configuration and control set. Values: `video`, `audio`, `live-video`, `live-audio`. Default: video.
- `skin`: The visual skin. Neutral has cleaner surfaces and the same controls as Default. Values: `default`, `neutral`, `compat`. Default: default. Applies when preset is not background-video.
- `media`: The media source or playback adapter. See the preset compatibility map below. Values: `background-video`, `hls-background-video`, `cloudflare`, `dash`, `hls`, `html5-audio`, `html5-video`, `mux-audio`, `mux-background-video`, `mux-video`, `spotify`, `tiktok`, `twitch`, `vimeo`, `youtube`. Default: the selected preset's first compatible media source.
- `extensions`: A comma-separated list of optional player extensions compatible with the selected player. Pass `none` when no extension is needed. Values: `none`, `google-cast`, `mux-data`. Default: mux-data for Mux media; none otherwise (reported as defaulted).
- `source-url`: The http:// or https:// media URL placed in the generated player example. Pass `demo` to choose the Video.js demo source for the selected media explicitly. Default: the Video.js demo source for the selected media (reported as defaulted).
- `package-manager`: The command runner used for app setup, packages, Shadcn, and the development server. Values: `npm`, `pnpm`, `yarn`, `bun`. Default: pnpm. Applies when method is not cdn with template none.
- `template`: The app setup and file layout. Values: `next`, `vite`, `start`, `react-router`, `astro`, `laravel`. Default: next for React; vite otherwise.
- `styling`: The Shadcn source styling. Compatible values depend on the framework. Values: `tailwind`, `css`. Default: tailwind for React; css otherwise. Applies when method=shadcn.
Run the command above without flags to see the corresponding CLI flags for every framework.
### Decide in this order
1. **Inspect the project.** Read package.json, framework config, and lockfiles to infer the framework, app setup, and package manager. React installs @videojs/react; HTML, Vue, and Svelte install @videojs/html.
2. **Choose the starting point.** Use existing when adapting a compatible project. Use new only when the user wants a new app or the intended workspace has no app. Confirm the choice when the workspace and request do not make it clear.
3. **Choose the player.** Use video unless the request signals another experience: audio, music, or podcasts use audio; a live stream uses live-video or live-audio; a muted, looping decorative video uses background-video. Ask only when those signals conflict.
4. **Choose the skin.** Use default unless the request asks for a minimal, cleaner, or more subtle look, which uses neutral; both contain the same controls. Ask only when those signals conflict.
5. **Choose the media.** Infer the adapter from the source when possible. Mux wins for Mux playback URLs: stream.mux.com/\.m3u8 or a bare playback ID uses mux-video, mux-audio, or mux-background-video rather than hls. Mux static renditions such as .mp4 or .m4a files use html5-video or html5-audio. Other .m3u8 URLs use hls.
6. **Choose extensions.** Mux Data is included by default for Mux video and audio sources. Add Google Cast when a standard or live video player with a ready-made skin should cast a compatible source. Use none when no extension is needed.
7. **Choose how to install.** This guide uses Shadcn to copy editable skin source. React uses the React source catalog; plain HTML uses the HTML source catalog. Vue and Svelte use packaged modules.
8. **Choose the styling.** For React, use tailwind in a new app or an existing Tailwind app; otherwise use css. HTML source uses css.
9. **Return one explicit plan.** Confirm the choices once, then pass every applicable query parameter, including `extensions=none` when no extension is needed and `source-url=demo` when there is no media URL yet. Check that Defaulted options says none. Adapt conditional setup steps and existing paths before changing files.
### Compatible media sources by preset
- `video`: `html5-video`, `hls`, `dash`, `mux-video`, `vimeo`, `youtube`, `cloudflare`, `tiktok`, `twitch`
- `audio`: `html5-audio`, `mux-audio`, `spotify`
- `live-video`: `hls`, `mux-video`
- `live-audio`: `mux-audio`
### App setup and Shadcn styling by framework
- `react`: templates `next`, `vite`, `start`, `react-router`, `astro`, `laravel`; styling `tailwind`, `css`
- `html`: templates `vite`, `astro`, `laravel`; styling `css`
### Installation pages
- [Packaged modules: React](https://videojs.org/docs/guides/installation/react.md)
- [Packaged modules: HTML](https://videojs.org/docs/guides/installation/html.md)
- [Packaged modules: Vue](https://videojs.org/docs/guides/installation/vue.md)
- [Packaged modules: Svelte](https://videojs.org/docs/guides/installation/svelte.md)
- [Editable Shadcn source: React source](https://videojs.org/docs/guides/installation/shadcn.md?framework=react)
- [Editable Shadcn source: HTML source](https://videojs.org/docs/guides/installation/shadcn.md?framework=html)
- [CDN: HTML from jsDelivr](https://videojs.org/docs/guides/installation/cdn.md)
## Selected options
- `method`: `shadcn`
- `framework`: `html`
- `project`: `existing`
- `preset`: `video`
- `skin`: `default`
- `media`: `html5-video`
- `extensions`: `none`
- `source-url`: `https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4`
- `package-manager`: `pnpm`
- `template`: `vite`
- `styling`: `css`
Defaulted options: project, preset, skin, source-url, media, extensions, template, package-manager, styling.
## Reproduce or change these instructions
```sh
npx @videojs/cli agents init --method shadcn --framework html --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --package-manager pnpm --template vite --styling css
```
## Configure app aliases
_Only when components.json is missing or does not use the standard https://ui.shadcn.com/schema.json schema._
Merge every app-alias block below, keeping the app's existing plugins and compiler options.
### `tsconfig.json`
_Merge this into the existing file, or create the file when it is missing._
```json
{
"compilerOptions": {
"paths": {
"@/*": [
"./src/*"
]
}
}
}
```
### `vite.config.ts`
_Merge this into the existing file, or create the file when it is missing._
```ts
import path from 'node:path';
import { defineConfig } from 'vite';
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(import.meta.dirname, './src'),
},
},
});
```
## Create components.json
_Only when components.json is missing._
Create the standard config in the app directory. Its components alias maps registry files to src/components.
### `components.json`
_Create this file._
```json
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {}
}
```
## Convert components.json
_Only when components.json exists but does not use the standard https://ui.shadcn.com/schema.json schema._
Replace the framework-specific config with the standard config below, but keep the existing values under aliases in place of the generated ones, so registry files install where the app already expects its components.
### `components.json`
_Replace the whole file with this block._
```json
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {}
}
```
## Add the Video.js Registry
This adds the selected @videojs catalog when the namespace is missing. If components.json already defines @videojs with another URL, replace that value with the URL from this command first because Shadcn skips configured namespaces.
```bash
pnpm dlx shadcn@latest registry add @videojs=https://shadcn.videojs.org/r/html/{name}.json
```
## Add the skin source
Make sure the working tree is clean or checkpointed so every added or replaced file is reviewable; ask before committing. The add command overwrites an existing Video.js skin so catalog and theme changes fully apply. Review and remove obsolete Video.js style files left by a previous catalog. The later media step restores the selected media component after an overwrite.
```bash
pnpm dlx shadcn@latest add @videojs/video --overwrite --yes
```
## Add your player
Use the aliases.components value from components.json when it differs from the generated @/components path: the skin file then lives under the directory that alias maps to instead of src/components, and the skin import uses that alias. Replace the placeholder in src/components/videojs/video/skin.html with the media snippet below. Size the video on the skin's root media-container by replacing its opening comment in the page with the complete updated skin markup. Merge the example into the existing Vite route or component that should render the player, and preserve unrelated content.
### `src/components/videojs/video/skin.html`
_Replace `` with this block._
```html
```
### `src/components/videojs/video/skin.html`
_Replace `` where the player should appear._
```html
```
_Then replace `` with the full contents of `src/components/videojs/video/skin.html`._
## Run your app
Start the development server and verify that the selected media plays.
_Long-running: start it in the background, verify the result, then stop it._
```bash
pnpm dev
```
> These are instructions only. Review and run the commands in your project; no files were modified. Shadcn copies the current Video.js registry source, while package installs use the version shown above.
That’s it! You now have a working Video.js player whose skin source lives in your project.
## Change the skin source
### HTML
Start in `/videojs//skin.html`. Follow the [Customize skins](https://videojs.org/docs/framework/html/guides/customize-skins#style-skin-source) guide for the files that control layout, colors, controls, and interactions.
## Choose what to do next
### HTML
#### Customize
- [Customize skin source](https://videojs.org/docs/framework/html/guides/customize-skins#style-skin-source): Change the installed layout, controls, styles, and interactions
- [UI components](https://videojs.org/docs/framework/html/guides/architecture#ui-components): Explore the building blocks used by skins and custom controls
- [Build your own component](https://videojs.org/docs/framework/html/guides/build-your-own-component): Connect custom UI to player state and actions
#### Deploy
- [Browser support](https://videojs.org/docs/framework/html/guides/browser-support): Check supported browsers and rendering environments
- [TypeScript](https://videojs.org/docs/framework/html/guides/typescript): Configure TypeScript for Video.js packages
- [Bundlers](https://videojs.org/docs/framework/html/guides/bundlers): Check bundler compatibility
- [Content Security Policy](https://videojs.org/docs/framework/html/guides/content-security-policy): Configure Content Security Policy for your player
---
# CDN Installation Guide
Load Video.js from jsDelivr and build an HTML video player without installing Video.js packages
Video.js can run directly from browser-ready files on jsDelivr. This HTML-only path does not install Video.js packages: choose a player, load its scripts, and add the generated custom-element markup to your page.
> **Tip: Coming from another player?**
>
> Follow the migration guide for [Video.js 8](https://videojs.org/docs/framework/html/guides/migrate-from-video-js-8), [Mux Player](https://videojs.org/docs/framework/html/guides/migrate-from-mux-player), [Plyr](https://videojs.org/docs/framework/html/guides/migrate-from-plyr), [Media Chrome](https://videojs.org/docs/framework/html/guides/migrate-from-media-chrome), or [Vidstack](https://videojs.org/docs/framework/html/guides/migrate-from-vidstack). Each maps your existing setup onto Video.js v10 instead of starting from scratch.
## AI Quickstart
Paste this prompt into your coding agent:
```
Install the Video.js skill: run `npx @videojs/cli agents skills` and follow the steps for the agent you are running in. If you can't run commands, follow the install instructions at https://github.com/videojs/skills instead. Then use the Video.js skill when you work on video or audio in this project. When installation details are needed, run `npx @videojs/cli agents init --method cdn --framework html` to print the version-matched choices and instructions without changing files.
```
## Installation options for coding agents
The web Markdown page contains the default installation. Add the query parameters below to its `.md` URL for a complete, validated variation. From a project or an offline docs bundle, run the CLI command below instead. Both paths use the same installation renderer and only return instructions; they do not modify a project.
This page fixes the installation method to `cdn` and the framework to `html`.
```sh
npx @videojs/cli agents init
```
### Query parameters
- `project`: Whether to adapt the current project or scaffold a new one. New projects need a named app setup. Values: `new`, `existing`. Default: existing.
- `preset`: The player configuration and control set. Values: `video`, `audio`, `live-video`, `live-audio`, `background-video`. Default: video.
- `skin`: The visual skin. Neutral has cleaner surfaces and the same controls as Default. Values: `default`, `neutral`, `compat`, `none`. Default: default. Applies when preset is not background-video.
- `media`: The media source or playback adapter. See the preset compatibility map below. Values: `background-video`, `hls-background-video`, `cloudflare`, `dash`, `hls`, `html5-audio`, `html5-video`, `mux-audio`, `mux-background-video`, `mux-video`, `spotify`, `tiktok`, `twitch`, `vimeo`, `youtube`. Default: the selected preset's first compatible media source.
- `extensions`: A comma-separated list of optional player extensions compatible with the selected player. Pass `none` when no extension is needed. Values: `none`, `google-cast`, `mux-data`. Default: mux-data for Mux media; none otherwise (reported as defaulted).
- `source-url`: The http:// or https:// media URL placed in the generated player example. Pass `demo` to choose the Video.js demo source for the selected media explicitly. Default: the Video.js demo source for the selected media (reported as defaulted).
- `package-manager`: The command runner used for app setup, packages, Shadcn, and the development server. Values: `npm`, `pnpm`, `yarn`, `bun`. Default: pnpm. Applies when method is not cdn with template none.
- `template`: The app setup and file layout. CDN defaults to `none` for an existing page and `vite` for a new app. Values: `vite`, `none`. Default: none.
Run the command above without flags to see the corresponding CLI flags for every framework.
### Decide in this order
1. **Inspect the project.** Read package.json, framework config, and lockfiles to infer the framework, app setup, and package manager. React installs @videojs/react; HTML, Vue, and Svelte install @videojs/html.
2. **Choose the starting point.** Use existing when adapting a compatible project. Use new only when the user wants a new app or the intended workspace has no app. Confirm the choice when the workspace and request do not make it clear.
3. **Choose the player.** Use video unless the request signals another experience: audio, music, or podcasts use audio; a live stream uses live-video or live-audio; a muted, looping decorative video uses background-video. Ask only when those signals conflict.
4. **Choose the skin.** Use default unless the request asks for a minimal, cleaner, or more subtle look, which uses neutral; both contain the same controls. Use none only when the project builds its own controls. Ask only when those signals conflict.
5. **Choose the media.** Infer the adapter from the source when possible. Mux wins for Mux playback URLs: stream.mux.com/\.m3u8 or a bare playback ID uses mux-video, mux-audio, or mux-background-video rather than hls. Mux static renditions such as .mp4 or .m4a files use html5-video or html5-audio. Other .m3u8 URLs use hls.
6. **Choose extensions.** Mux Data is included by default for Mux video and audio sources. Add Google Cast when a standard or live video player with a ready-made skin should cast a compatible source. Use none when no extension is needed.
7. **Choose how to install.** This guide uses CDN scripts for plain HTML. Use an existing page when one is available, and scaffold a minimal Vite app only when no app exists.
8. **Return one explicit plan.** Confirm the choices once, then pass every applicable query parameter, including `extensions=none` when no extension is needed and `source-url=demo` when there is no media URL yet. Check that Defaulted options says none. Adapt conditional setup steps and existing paths before changing files.
### Compatible media sources by preset
- `video`: `html5-video`, `hls`, `dash`, `mux-video`, `vimeo`, `youtube`, `cloudflare`, `tiktok`, `twitch`
- `audio`: `html5-audio`, `mux-audio`, `spotify`
- `live-video`: `hls`, `mux-video`
- `live-audio`: `mux-audio`
- `background-video`: `background-video`, `hls-background-video`, `mux-background-video`
### App setup by framework
- `html`: templates `vite`, `none`
### Installation pages
- [Packaged modules: React](https://videojs.org/docs/guides/installation/react.md)
- [Packaged modules: HTML](https://videojs.org/docs/guides/installation/html.md)
- [Packaged modules: Vue](https://videojs.org/docs/guides/installation/vue.md)
- [Packaged modules: Svelte](https://videojs.org/docs/guides/installation/svelte.md)
- [Editable Shadcn source: React source](https://videojs.org/docs/guides/installation/shadcn.md?framework=react)
- [Editable Shadcn source: HTML source](https://videojs.org/docs/guides/installation/shadcn.md?framework=html)
- [CDN: HTML from jsDelivr](https://videojs.org/docs/guides/installation/cdn.md)
## Selected options
- `method`: `cdn`
- `framework`: `html`
- `project`: `existing`
- `preset`: `video`
- `skin`: `default`
- `media`: `html5-video`
- `extensions`: `none`
- `source-url`: `https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4`
- `template`: `none`
Defaulted options: project, preset, skin, source-url, media, extensions, template.
## Reproduce or change these instructions
```sh
npx @videojs/cli agents init --method cdn --framework html --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --template none
```
## Load Video.js
Add these module scripts to the page head. Module scripts are deferred, so they wait for the page.
### `index.html` (head)
_Merge this into the page ``._
```html
```
## Add your player
Add this markup inside the page body where the player should appear.
### `index.html` (body)
_Merge this into the page `` where the player should appear._
```html
```
> These are instructions only. Review and run the commands in your project; no files were modified.
That’s it! You now have a working Video.js player without installing Video.js packages.
## Own the UI
Packaged skins keep their controls and layout inside Video.js. When you need to add, remove, rearrange, or deeply restyle controls, use Shadcn to add the skin source to your project. Its components, layout, styles, and interactions become local files you can change.
- [Install Video.js with Shadcn](https://videojs.org/docs/guides/installation/shadcn?framework=html#choose-how-to-install): Add editable skin source and build a working React or HTML player
## Choose what to do next
### Customize
- [Customize skins](https://videojs.org/docs/framework/html/guides/customize-skins#style-a-packaged-skin): Change colors, typography, sizing, and poster presentation
- [Install with Shadcn](https://videojs.org/docs/guides/installation/shadcn?framework=html): Add editable skin source and build a working React or HTML player
- [Internationalize the player](https://videojs.org/docs/framework/html/guides/internationalization): Load another locale or add your own translations
### Deploy
- [CDN files and URLs](https://videojs.org/docs/framework/html/guides/cdn): Understand CDN URLs, bundles, stylesheets, locales, and shared chunks
- [Browser support](https://videojs.org/docs/framework/html/guides/browser-support): Check supported browsers and rendering environments
- [Content Security Policy](https://videojs.org/docs/framework/html/guides/content-security-policy): Configure Content Security Policy for your player
- [Self-host the player](https://videojs.org/docs/framework/html/guides/self-hosting): Serve the player from your own origin for offline or restricted-network deployments
---
# Build your own UI component
Create custom player controls that read state, dispatch actions, and stay accessible.
Custom components subscribe to player state and dispatch actions, like built-in controls.
## You might not need a custom component
Before building from scratch, check if an existing approach covers your use case:
- **Restyle a control**: use CSS custom properties and data attributes. See [UI components](https://videojs.org/docs/framework/html/guides/ui-components).
- **Rearrange or remove controls**: add the skin source to your project, then modify it. See [Customize skins](https://videojs.org/docs/framework/html/guides/customize-skins#style-skin-source).
Build a custom component when you need new behavior, a new state display, or integration with an external system.
## Place your component in the player
Your element needs to be inside [``](https://videojs.org/docs/framework/html/reference/components/player) to access state. Place it inside [``](https://videojs.org/docs/framework/html/reference/components/player-container) if it should also participate in fullscreen and respond to user activity. `` slots its children into ``, so a child of the skin works:
```html
Skip intro
```
Extend `UIElement` from `@videojs/html` so `PlayerController` can schedule DOM updates when state changes:
```ts
import { UIElement, PlayerController, playerContext, selectTime, type PropertyValues } from '@videojs/html';
class SkipIntroButtonElement extends UIElement {
#player = new PlayerController(this, playerContext, selectTime);
update(changed: PropertyValues) {
super.update(changed);
const time = this.#player.value;
}
}
```
If your element starts listeners, observers, or other work, stop it in `disconnectedCallback()` and call the superclass lifecycle methods so inherited cleanup runs too. The browser can connect and disconnect the same element many times.
## Full example
A “skip intro” button that appears during the first 30 seconds of playback and seeks past the intro when clicked.
**skip-intro-button.ts**
```ts
import {
UIElement,
PlayerController,
playerContext,
selectTime,
selectPlayback,
type PropertyValues,
} from '@videojs/html';
class SkipIntroButtonElement extends UIElement {
#time = new PlayerController(this, playerContext, selectTime);
#playback = new PlayerController(this, playerContext, selectPlayback);
#disconnect: AbortController | null = null;
connectedCallback() {
super.connectedCallback();
this.#disconnect?.abort();
this.#disconnect = new AbortController();
const { signal } = this.#disconnect;
this.setAttribute('role', 'button');
this.setAttribute('aria-label', 'Skip intro');
this.setAttribute('tabindex', '0');
this.addEventListener('click', this.#handleActivate, { signal });
this.addEventListener('keydown', this.#handleKeydown, { signal });
this.addEventListener('keyup', this.#handleKeyup, { signal });
}
disconnectedCallback() {
super.disconnectedCallback();
// Removes all listeners registered with this signal
this.#disconnect?.abort();
this.#disconnect = null;
}
update(changed: PropertyValues) {
super.update(changed);
const time = this.#time.value;
const playback = this.#playback.value;
// Features are configured per-player, so a feature may not be available
if (!time || !playback) return;
const visible = time.currentTime < 30 && !playback.paused;
this.toggleAttribute('data-visible', visible);
this.setAttribute('tabindex', visible ? '0' : '-1');
}
#handleActivate = () => {
this.#time.value?.seek(30);
};
#handleKeydown = (event: KeyboardEvent) => {
if (event.key === 'Enter') {
event.preventDefault();
this.#handleActivate();
} else if (event.key === ' ') {
// Prevent Space from scrolling the page
event.preventDefault();
}
};
// ARIA button pattern: Space activates on keyup, not keydown
#handleKeyup = (event: KeyboardEvent) => {
if (event.key === ' ') {
this.#handleActivate();
}
};
}
customElements.define('skip-intro-button', SkipIntroButtonElement);
```
**skip-intro-button.css**
```css
skip-intro-button {
position: absolute;
bottom: 5rem;
right: 1rem;
opacity: 0;
pointer-events: none;
transition: opacity 200ms;
}
skip-intro-button[data-visible] {
opacity: 1;
pointer-events: auto;
}
```
Your element needs to be inside [``](https://videojs.org/docs/framework/html/reference/components/player) to access state. Place it inside [``](https://videojs.org/docs/framework/html/reference/components/player-container) if it should also participate in fullscreen and respond to user activity. `` slots its children into ``, so a child of the skin works:
```html
Skip intro
```
## How it works
Custom components read player state and dispatch actions through [features](https://videojs.org/docs/framework/html/guides/features). Each feature exposes a set. Here are some features you might reach for first:
| State | Actions | Feature |
| --- | --- | --- |
| `paused`, `ended` | `play()`, `pause()` | [Playback](https://videojs.org/docs/framework/html/reference/api/feature-playback) |
| `currentTime`, `duration` | `seek()` | [Time](https://videojs.org/docs/framework/html/reference/api/feature-time) |
| `volume`, `muted` | `setVolume()`, `setMuted()` | [Volume](https://videojs.org/docs/framework/html/reference/api/feature-volume) |
| `isFullscreen` | `requestFullscreen()`, `exitFullscreen()` | [Fullscreen](https://videojs.org/docs/framework/html/reference/api/feature-fullscreen) |
The API reference lists every feature with the state and actions it adds.
Extend `UIElement` from `@videojs/html` so [`PlayerController`](https://videojs.org/docs/framework/html/reference/api/player-controller) can schedule DOM updates when state changes, and access state and actions with a feature selector:
```ts
import { PlayerController, playerContext, selectPlayback } from '@videojs/html';
// Subscribe to a feature — triggers update() when its state changes
#playback = new PlayerController(this, playerContext, selectPlayback);
// In update():
const playback = this.#playback.value;
if (playback?.paused) {
playback.play();
}
```
Each selector returns both state and actions for that feature. Use separate controllers when you need multiple features (the [full example](https://videojs.org/docs/framework/html/guides/build-your-own-component#full-example) demonstrates this).
Without a selector, `PlayerController` returns the full store without subscribing to changes. Create the controller with the typed context that [`createPlayer`](https://videojs.org/docs/framework/html/reference/api/html-create-player) returns — the shared `playerContext` types the store’s members as `unknown` — and guard the value, which stays `undefined` until a player provides the store:
```ts
import { createPlayer, PlayerController } from '@videojs/html';
import { videoFeatures } from '@videojs/html/video';
const { playerContext: videoPlayerContext } = createPlayer({ features: videoFeatures });
#store = new PlayerController(this, videoPlayerContext);
// Call any action
this.#store.value?.play();
this.#store.value?.setVolume(0.5);
```
Custom controls also need real button semantics — the examples above set the accessible name, keyboard focus, and (because a custom element is not a native `