HTML Media Elements Table

PieceWhat it doesField note
<video> / <audio>Embed media with a native UI option Always add playsinline or iOS plays fullscreen
<source>Multiple format candidatesBrowser takes the FIRST it understands - list modern codecs first
<track>Subtitles and captionskind=captions; a default track must exist for accessibility
controlsShow the native UIWithout it the element is invisible and only script-driven
muted + autoplayThe only autoplay combo browsers allowUnmuted autoplay is blocked by policy everywhere
playsinlinePlay inside the page boxWithout it iOS hijacks the screen
posterPreview frame before playAlso hides the first-frame flash while metadata loads
preload="metadata"Fetch only duration and dimensionsnone = nothing, auto = browser decides - metadata is the polite default
loopRestart automaticallyCombine with muted for ambient backgrounds
play() / pause()Script controlplay() returns a promise - autoplay refusal rejects it, catch it
currentTime / durationSeek and total lengthduration is NaN until loadedmetadata fires
volume / muted propertyLevel and mute stateVolume is 0.0-1.0, not percent
Reference: MDN HTMLMediaElement. The policy landscape in one line: browsers allow autoplay only when muted (or after user interaction), so background-video patterns are always muted + playsinline + autoplay, and any play() call should handle its promise rejection - that is the browser telling you the user has not interacted yet. Bottom line: source-first fallbacks, a captions track, and the muted trio cover 95 percent of real deployments. Related tools: DOM events table (loadedmetadata, timeupdate), HTML forms table, and web vitals table - video posters protect your LCP.

Native HTML media is more capable than its reputation: one <video> element covers formats, captions, previews, and script control - the plugins died a decade ago. The table below is the working twelve: the elements, the attributes that decide playback behavior, and the script surface that everything else builds on.

Bottom line: the autoplay policy is the landscape everything else adapts to. Browsers allow automatic playback only when the media is muted (or after the user has interacted with the page), which is why every background-video pattern on the web is the same trio: autoplay + muted + playsinline. Unmuted autoplay is blocked by every major browser, and the muted trio is not a workaround - it is the supported path.

The honest part: iOS Safari is its own chapter. Without playsinline, a playing video takes over the whole screen; preload is advisory, not binding; and duration stays NaN until loadedmetadata fires. Testing on one engine is testing on half the market - the table's notes carry the per-engine landmines.

How to use

  1. Compose from the top: the video or audio element, one or more source children, a captions track, the behavior attributes.
  2. Order source elements modern-codec-first - the browser takes the first one it can play and never looks back.
  3. Control from script via the API rows: play() (catch its rejection - it is the autoplay policy speaking), currentTime for seeking, volume between 0 and 1.

Frequently asked questions

Why won't my video autoplay?

Because it has sound. Browser autoplay policy allows automatic playback only for muted media, or after the user has interacted with the page (a click anywhere counts). The fix for background and ambient video: autoplay muted playsinline loop together. For content video, the answer is not to fight the policy - show a poster frame with your own play button, and the click both satisfies the interaction requirement and is what the user wanted anyway.

What does the preload attribute actually control?

How eagerly the browser fetches the media before play: none downloads nothing until play, metadata fetches just enough for duration and dimensions, auto lets the browser decide (usually a chunk). The catch in the name: it is a hint, not a command - iOS Safari historically ignores it, and browsers on metered connections downgrade it themselves. preload="metadata" is the polite default: it makes duration and poster work without pulling megabytes.

How do I add subtitles or captions to a video?

With a <track kind="captions" src="subtitles.vtt" srclang="en" label="English"> child inside the video element - WebVTT format, one track per language, and exactly one with the default attribute for the starting language. Captions are not optional polish: they serve deaf viewers, sound-off social feeds, and SEO in one move. The common bug is a track that loads but stays empty - the VTT file needs the WEBVTT header as its first line, and the server needs a text/vtt content type.

Why does my video play fullscreen on iPhones?

Missing playsinline. Without it, iOS Safari plays video in fullscreen theater mode by default - the page disappears. playsinline keeps playback inside the layout box, which is what every embedded and background video needs. The complete quiet-play recipe is autoplay muted loop playsinline; drop any one of the four and some device class will behave differently than your desktop test did.

Related tools