# UI components

How Video.js UI components use focused elements, data attributes for state, and compound composition.

UI components are controls like buttons, sliders, and time displays.

Visible UI components render at most one HTML element, taking inspiration from projects like [shadcn/ui](https://ui.shadcn.com/) and [Base UI](https://base-ui.com/). This approach gives you control over styling and behavior while handling the complex interactions for you. State-only components render no markup, and controls can skip rendering when their feature is unavailable.

Individual controls provide interaction, accessible names, and state. You add their visible text or icons and CSS. Sliders also need the child elements and styles shown on their reference pages.

## Where to put your components

Each `@videojs/html/ui/*` import registers exactly one custom element. Compound components such as controls, sliders, menus, and dialogs need an import for the root and for every part you render, so a `<media-controls-content>` inside `<media-controls>` needs both `ui/controls` and `ui/controls-content`. Without its import, a part stays a plain element and never receives its state attributes. Each reference page lists the imports for its anatomy, and the skin entry points register everything their layout uses.

UI components can go anywhere inside a [`<video-player>`](https://videojs.org/docs/framework/html/reference/components/player).

However, you should consider placing your components in `<media-container>`. Components in `<media-container>` will go fullscreen with the player, respond to user activity, and more.

- [Read more about `<media-container>`](https://videojs.org/docs/framework/html/reference/components/player-container)

## Styling and customization

For components you add yourself, select them by their custom element name. Use the documented state `data-*` attributes and CSS custom properties to style them.

### Add icons

Import `@videojs/html/icons/element` once in your `app.ts` to register `<media-icon>`. Choose an icon with `name`. Set `family="minimal"` to use the Minimal skin’s icon designs. You can also use your own text or SVG.

```ts
import '@videojs/html/icons/element';
```

```html
<media-play-button class="my-play-button">
  <media-icon class="play-icon" name="play"></media-icon>
  <media-icon class="pause-icon" name="pause"></media-icon>
</media-play-button>
```

### Style components with state

Components add `data-*` attributes to describe their current state. For example, a play button adds `data-paused` while the media is paused. Use those attributes in CSS:

```css
.my-play-button .pause-icon {
  display: none;
}

.my-play-button:defined:not([data-paused]) .play-icon {
  display: none;
}

.my-play-button:defined:not([data-paused]) .pause-icon {
  display: inline-flex;
}
```

The browser matches `:defined` after it loads the custom element. This keeps the play icon visible while JavaScript loads.

Each component’s reference page documents its full set of data attributes.

Some components also expose **CSS custom properties** for continuous values like fill percentage and pointer position. Sliders, for example, set `--media-slider-fill` and `--media-slider-pointer`. See individual component reference pages for specifics.

## Compound components

Complex interactions are split into composable parts. A parent manages shared state while children consume it. Each visible part owns at most one element.

```html
<media-volume-slider orientation="vertical">
  <media-slider-track>
    <media-slider-fill></media-slider-fill>
  </media-slider-track>
  <media-slider-thumb></media-slider-thumb>
</media-volume-slider>
```

---

HTML documentation: https://videojs.org/docs/framework/html/llms.txt
All documentation: https://videojs.org/llms.txt
