Skip to main content

Video Component

Base Video

The video block wraps a native <video> element and a video__controls bar. The control bar is a flex row that sizes to 100% of the container. Time labels are <span> elements using the video__timestamp class. The scrubber range input uses video__scrubber to fill remaining space. All buttons in the bar use video__control — a bare, unstyled button with only a pressed state.

0:001:23
<div class="video">
  <video src="..." preload="metadata" aria-label="Sample video" />
  <div class="video__controls" role="group" aria-label="Video controls">
    <button class="video__control" type="button" aria-label="Play">
      <svg class="icon icon--20" width="20" height="20" aria-hidden="true">
        <use href="#icon-play-20" />
      </svg>
    </button>
    <span class="video__timestamp"> 0:00 </span>
    <input
      class="video__scrubber"
      type="range"
      min="0"
      max="100"
      value="0"
      step="0.1"
      aria-label="Seek"
    />
    <span class="video__timestamp"> 1:23 </span>
    <button class="video__control" type="button" aria-label="Fullscreen">
      <svg class="icon icon--16" width="16" height="16" aria-hidden="true">
        <use href="#icon-expand-16" />
      </svg>
    </button>
  </div>
</div>

Popover Controls

The control bar may contain buttons that open popovers. video__popover-container anchors a video__popover to its trigger, shown while the trigger is aria-expanded="true". Add video__popover-container--hover instead to reveal the popover on hover and focus, as the volume slider does.

0:001:23
<div class="video">
  <video src="..." preload="metadata" aria-label="Sample video" />
  <div class="video__controls" role="group" aria-label="Video controls">
    <button class="video__control" type="button" aria-label="Play">
      <svg class="icon icon--20" width="20" height="20" aria-hidden="true">
        <use href="#icon-play-20" />
      </svg>
    </button>
    <span class="video__timestamp"> 0:00 </span>
    <input
      class="video__scrubber"
      type="range"
      min="0"
      max="100"
      value="0"
      step="0.1"
      aria-label="Seek"
    />
    <span class="video__timestamp"> 1:23 </span>
    <span class="video__popover-container">
      <button class="video__control" type="button" aria-label="Closed captions">
        <svg class="icon icon--16" width="16" height="16" aria-hidden="true">
          <use href="#icon-closed-caption-16" />
        </svg>
      </button>
      <span class="video__popover">
        <!-- menu -->
      </span>
    </span>
    <span class="video__popover-container video__popover-container--hover">
      <button
        class="video__control"
        type="button"
        aria-label="Mute"
        aria-pressed="false"
      >
        <svg class="icon icon--16" width="16" height="16" aria-hidden="true">
          <use href="#icon-audio-high-16" />
        </svg>
      </button>
      <div class="video__popover">
        <input
          class="video__volume"
          type="range"
          min="0"
          max="100"
          value="80"
          aria-label="Volume"
        />
      </div>
    </span>
    <button class="video__control" type="button" aria-label="Fullscreen">
      <svg class="icon icon--16" width="16" height="16" aria-hidden="true">
        <use href="#icon-expand-16" />
      </svg>
    </button>
  </div>
</div>

Control Bar Variants

Without a scrubber, video__timestamp--remaining sizes the countdown to its content and video__spacer pushes the buttons to the trailing edge. While the media plays, video__controls--hidden fades the whole bar out; it returns whenever something inside it takes focus.

-0:54
<div class="video">
  <video src="..." preload="metadata" aria-label="Sample video" />
  <div
    class="video__controls video__controls--hidden"
    role="group"
    aria-label="Video controls"
  >
    <span class="video__timestamp video__timestamp--remaining"> -0:54 </span>
    <span class="video__spacer" />
    <button class="video__control" type="button" aria-label="Play">
      <svg class="icon icon--20" width="20" height="20" aria-hidden="true">
        <use href="#icon-play-20" />
      </svg>
    </button>
  </div>
</div>

Overlays

video__overlay centers content over the video for error and loading states (add video__overlay--transparent for a spinner without a scrim). video__play-overlay is a full-bleed poster play button, and video__nav is a full-bleed overlay link rendered under the control bar.

An error has occurred
<div class="video">
  <video src="..." preload="metadata" aria-label="Sample video" />
  <a
    class="video__nav"
    href="https://www.ebay.com"
    aria-label="Watch on eBay"
  />
  <button class="video__play-overlay" type="button" aria-label="Play">
    <svg class="icon icon--64" width="64" height="64" aria-hidden="true">
      <use href="#icon-play-filled-64-colored" />
    </svg>
  </button>
  <div class="video__overlay video__overlay--transparent">
    <!-- progress-spinner -->
  </div>
  <div class="video__overlay">
    <svg class="icon icon--24" width="24" height="24" aria-hidden="true">
      <use href="#icon-attention-24" />
    </svg>
    <div class="video__overlay-text">An error has occurred</div>
  </div>
</div>