HTML Video

The <video> element lets you embed a movie clip, screencast, or any video file directly in a web page, playable by the browser’s own built-in player without any plugin. Before HTML5 introduced it, playing video on the web required proprietary plugins like Flash or Silverlight. Today <video> is a native, accessible, scriptable part of the DOM, and understanding its attributes, source-fallback system, and captioning support is essential for building modern media-rich pages.

Overview / How it works

The <video> element is a replaced element, much like <img>, but it is far richer: it exposes a real user interface (when controls is present), it has playback state (paused, currentTime, duration, volume), and it fires events (play, pause, ended, timeupdate) that JavaScript can respond to. This lesson focuses on the markup side — the attributes and child elements you write in HTML.

When the browser’s HTML parser encounters a <video> tag, it creates a corresponding node in the DOM tree and begins evaluating how to load media for it. There are two ways to specify what to play:

  • A single src attribute directly on the <video> tag, pointing to one file.
  • One or more <source> child elements, each offering a different file (usually different formats/codecs), letting the browser pick the first one it can actually play.

Browsers do not all support the same video codecs. Common formats you’ll encounter are MP4 (H.264 video, AAC audio — supported almost everywhere), WebM (VP8/VP9 or AV1 — supported by Chrome, Firefox, Edge), and Ogg (Theora — largely obsolete now). Because of this fragmentation, offering multiple <source> elements is the most robust approach for public-facing sites, even though a single MP4 file covers the overwhelming majority of modern browsers today.

Anything placed between the opening and closing <video> tags that is not a <source> or <track> element is treated as fallback content — it is only rendered if the browser does not support the <video> element at all (extremely rare today, but still good practice, and it’s where you can put a plain download link).

The video itself does not play automatically and shows no visible controls by default unless you tell it to — this is a deliberate, accessibility- and bandwidth-conscious default. You must explicitly opt in to a visible control bar and to autoplay behavior using attributes.

Syntax

<video src="movie.mp4" controls width="640" height="360" poster="cover.jpg">
  Your browser does not support the video tag.
</video>
Attribute Purpose
src URL of the video file (omit this if you use child <source> elements instead).
controls Boolean attribute. Shows the browser’s default play/pause, volume, seek bar, and fullscreen UI.
width / height Sets the rendering box size in pixels, reserving space before the video loads to avoid layout shift.
poster URL of an image shown before playback starts, in place of the first frame.
autoplay Boolean attribute. Starts playback automatically. Most browsers require the video to also be muted for this to work.
muted Boolean attribute. Starts the video with audio silenced.
loop Boolean attribute. Restarts playback from the beginning when it reaches the end.
preload Hints how much to load before playback: none, metadata, or auto.
playsinline Boolean attribute. On mobile browsers (notably iOS Safari), allows inline playback instead of forcing fullscreen.
crossorigin Configures CORS behavior when the video is on another origin, needed if a canvas will read its pixel data.

Examples

Example 1: A basic controlled video

<video src="intro.mp4" controls width="480" height="270">
  Sorry, your browser doesn't support embedded video.
</video>

Result: A 480 by 270 pixel video player appears with a visible control bar (play/pause button, seek bar, volume, and fullscreen icon). The video does not start until the visitor presses play. If the browser somehow doesn’t support <video>, the fallback sentence displays as plain text instead.

This is the pattern you should reach for by default: explicit controls so the visitor is in charge of playback, and explicit dimensions so the page doesn’t jump around as the video loads.

Example 2: Multiple sources with a poster image

<video controls width="640" height="360" poster="thumbnail.jpg" preload="metadata">
  <source src="trailer.webm" type="video/webm">
  <source src="trailer.mp4" type="video/mp4">
  <p>
    Your browser doesn't support HTML video. Here is a
    <a href="trailer.mp4">link to download the video</a> instead.
  </p>
</video>

Result: Before playback, the browser displays the thumbnail.jpg image inside a 640 by 360 box with a control bar overlaid. The browser evaluates the <source> elements in order and loads the first one whose type it can play — a Chrome or Firefox user typically gets the WebM file, while a browser without WebM support falls through to the MP4 file. Because preload="metadata" is set, the browser fetches just enough of the file to know its duration and dimensions without downloading the whole thing up front.

Example 3: Muted autoplay loop with captions

<video autoplay muted loop playsinline width="560" height="315">
  <source src="ambient-loop.mp4" type="video/mp4">
  <track kind="captions" src="captions-en.vtt" srclang="en" label="English" default>
  Video not supported.
</video>

Result: The video begins playing immediately on page load with no sound and no visible control bar, and loops continuously once it reaches the end — a common pattern for decorative background clips. The <track> element attaches an English caption file; because it has the default attribute, captions display automatically if the visitor enables them or if the browser is configured to show captions by default. Note there are no controls here, so the visitor cannot pause it from the UI unless JavaScript adds that ability — this only suits genuinely decorative, muted content, never anything with meaningful audio or information.

How it works step by step

  1. The HTML parser reaches the <video> start tag and creates a video element node in the DOM, along with any <source> and <track> children.
  2. The browser resolves which media resource to use: if src is present on <video> itself, that wins; otherwise it walks the <source> children in document order and selects the first one it reports it can play (checked via the type attribute and, when needed, by probing the actual file).
  3. If preload or autoplay call for it, the browser begins fetching the media resource (or just its metadata).
  4. Until the first frame is available, the browser paints the poster image if one was given, or a blank area sized by width/height if not.
  5. If controls is present, the browser constructs its native UI (play button, scrubber, volume, fullscreen toggle) and lays it over the video box.
  6. If any <track> elements are present, the browser loads the referenced WebVTT files and makes caption/subtitle cues available for display and for the accessibility tree.
  7. None of this markup runs any script — playback, pausing, and volume are handled entirely by the browser’s media engine, exposed to JavaScript only if you choose to use the Media API separately.

Common Mistakes

Mistake 1: Relying on autoplay with sound

<video src="promo.mp4" autoplay controls></video>

This looks reasonable but will silently fail to autoplay in almost every modern browser, because autoplay is only honored when the video is also muted (unmuted autoplay was disabled industry-wide to stop pages blasting sound on load). The fix is to add muted:

<video src="promo.mp4" autoplay muted controls></video>

Mistake 2: Forgetting a fallback and multiple formats

<video src="clip.mov"></video>

A single, less-common container like .mov may not be decodable by many browsers at all, and there is no fallback text or link for visitors who get nothing. Prefer widely-supported formats and give visitors a way out:

<video controls>
  <source src="clip.mp4" type="video/mp4">
  <source src="clip.webm" type="video/webm">
  <a href="clip.mp4">Download the video</a>
</video>

Mistake 3: Nesting source tags incorrectly

<video controls>
  <source src="movie.mp4">
    <source src="movie.webm">
  </source>
</video>

<source> is a void element — it never wraps content and must never contain another <source>. Each one is a flat, self-contained sibling:

<video controls>
  <source src="movie.mp4" type="video/mp4">
  <source src="movie.webm" type="video/webm">
</video>

Best Practices

  • Always include controls unless the video is purely decorative, muted, and looping — visitors should be able to pause and adjust volume themselves.
  • Provide a <track kind="captions"> for any video with spoken dialogue, both for deaf and hard-of-hearing visitors and for anyone watching with sound off.
  • Set explicit width and height so the layout doesn’t shift while the video loads.
  • Use a poster image so the page never shows a jarring black box before playback begins.
  • Offer at least an MP4 source for maximum compatibility, and add WebM for smaller file sizes on browsers that support it.
  • Never pair autoplay with unmuted audio — it will be blocked, and it’s a poor experience even when it isn’t.
  • Use preload="none" or "metadata" on pages with many videos to avoid downloading media the visitor may never play.
  • Remember that styling the player’s appearance (size aside) is the job of CSS, not HTML attributes.

Practice Exercises

  1. Write a <video> element with visible controls, a poster image, and two <source> children offering an MP4 and a WebM version of the same clip.
  2. Take the video from exercise 1 and add an English caption track using <track>, marking it as the default track.
  3. Write a muted, autoplaying, looping background video with playsinline, and explain in a comment (in your own notes, not the markup) why controls should be omitted or handled carefully in this case.

Summary

  • The <video> element embeds playable video natively, without plugins.
  • Use a single src for one file, or multiple <source> children to offer format fallbacks the browser chooses between.
  • controls, autoplay, muted, and loop are boolean attributes that shape playback behavior; unmuted autoplay is blocked by browsers.
  • poster, width, and height improve the loading experience and prevent layout shift.
  • <track> adds captions or subtitles from a WebVTT file, which is essential for accessibility.
  • Content between the tags is fallback text/links shown only if <video> itself is unsupported.