Skip to content
FrameworkStyle

media-container

The player's visual and interaction surface for layout, fullscreen, focus, and user activity.

The <media-container> is the player’s physical surface. It defines the visual boundary, registers the fullscreen and activity target, and gives gesture and hotkey elements a shared interaction surface. It lives inside a <video-player>.

<video-player>
  <media-container>
    <video src="video.mp4"></video>
    <media-controls><media-controls-content>...</media-controls-content></media-controls>
  </media-container>
</video-player>

How it’s created

Import the standard player entry point. It registers both <video-player> and <media-container>:

import '@videojs/html/video/player';
<video-player>
  <media-container>
    <video src="video.mp4"></video>
  </media-container>
</video-player>

For custom behavior, extend the same ContainerElement used by the built-in player:

import { ContainerElement } from '@videojs/html';

class MyContainer extends ContainerElement {}
customElements.define('my-container', MyContainer);

Extending ContainerElement automatically registers the element with the nearest player when it connects and releases that registration when it disconnects.

Import @videojs/html/ui/container when you only need to register the standard <media-container> element.

What it does

Layout and fullscreen

The container is the visual box around your media and controls. Put sizing, aspect ratio, positioning, and visual boundaries here — on Container, not Player. Place overlays inside it, use it as their positioning context, and measure it when your app needs the rendered player size.

.player-surface {
  position: relative;
  display: block;
  width: 640px;
  aspect-ratio: 16 / 9;
}
<media-container class="player-surface">
  <video src="video.mp4"></video>
  <media-controls><media-controls-content>...</media-controls-content></media-controls>
</media-container>

When the user goes fullscreen, the container goes fullscreen — not the video element. This keeps controls and other UI visible on top of the video, since they’re children of the container.

Custom video elements such as <mux-video> and <hlsjs-video> do not create their own layout boxes: their inner <video> fills the parent. Size and measure <media-container>, not <mux-video> or <hlsjs-video>. Native <video> and <audio> elements still render their own boxes.

Media attachment

Media discovery is handled by the player provider, not the container. Custom media elements like <hlsjs-video> register themselves via context when they connect. Plain <video> and <audio> elements are tracked automatically, including when they are added, removed, or replaced after connection. No slot="media" attribute is needed.

Interaction surface

The container is where user intent enters the player. It listens for physical interaction on its surface and translates that into player behavior:

  • User activity — Mouse movement, touch, and keyboard activity within the container drive idle detection. This is how controls know when to show and hide.
  • Gestures — Tap and double-tap actions, optionally limited by pointer type and left, center, or right region. Configured via the Gesture component.
  • Keyboard controls — Spacebar to play/pause, arrow keys to seek, and other keyboard shortcuts scoped to the container. Configured via the Hotkey component.

Each container owns one popup group. Opening a root menu or popover closes the previously open popup in that container. A popup rendered outside the container still manages its own open state, but it does not participate in the container’s group.

Relationship to skins

A skin is a container plus UI controls. When you use a packaged skin, the container is built in — you don’t need to add one yourself.

Style <video-skin> for the player’s outer size and aspect ratio. Importing the skin registers the styles that make the built-in container fill that space and position the media, controls, poster, and overlays.

If you omit <video-skin> to build custom UI, render and style <media-container> yourself. See Layout and fullscreen for the complete layout example.

Inside vs. outside the container

Player gives components access to state and actions. Container layers on physical behaviors — fullscreen, activity detection, and gesture handling. Components work in both places; the container just adds those extras.

<video-player>
  <media-container>
    <video src="video.mp4"></video>
    <media-controls><media-controls-content>...</media-controls-content></media-controls>  <!-- fullscreen, activity detection, gestures -->
  </media-container>

  <media-transcript></media-transcript>     <!-- state & actions, but no container behaviors -->
  <playlist-sidebar></playlist-sidebar>     <!-- state & actions, but no container behaviors -->
</video-player>

A play button outside the container still reads playback state and can toggle play/pause — it just won’t go fullscreen with the player or respond to the container’s idle state.