Key takeaways
- Use <video> with an MP4 (H.264/AAC) source; add WebM first if you want smaller files.
- Add controls, a poster and preload="metadata" — autoplay only when muted and inline.
- Reserve space with aspect-ratio and use object-fit to fit any layout.
- Add captions with <track> for accessibility.
- For YouTube or Vimeo use their iframe players; for many videos use a gallery.
Basic example
<video controls width="640" poster="poster.jpg"> <source src="movie.webm" type="video/webm"> <source src="movie.mp4" type="video/mp4"> Your browser does not support HTML5 video. </video>
Attributes
| Attribute | What it does |
|---|---|
| controls | Shows play, volume and fullscreen controls |
| autoplay | Starts playback automatically (needs muted) |
| muted | Starts without sound |
| loop | Replays when it ends |
| playsinline | Plays inline on iPhone |
| poster | Image shown before playback |
| preload | none / metadata / auto — how much to load up front |
| width / height | Intrinsic size (use CSS for responsive) |
Responsive video
video{width:100%;height:auto;aspect-ratio:16/9}Captions
<video controls> <source src="movie.mp4" type="video/mp4"> <track kind="captions" src="captions.vtt" srclang="en" label="English" default> </video>
Embedding YouTube isn’t the video tag
YouTube and Vimeo videos can’t be played with <video>; use their iframe players — see our YouTube embed code generator.
Need a gallery of YouTube, Vimeo and hosted videos instead of one player? Use a widget.
Try Elfsight Video Gallery →Formats and browser support
| Format | Support | Use it for |
|---|---|---|
| MP4 (H.264 + AAC) | All modern browsers | The default choice |
| WebM (VP9 / AV1) | All modern browsers except some older Safari versions | Smaller files — offer as an extra <source> |
| HLS (.m3u8) | Native in Safari; others need hls.js | Long videos and live streams |
Control the video with JavaScript
const v = document.querySelector("video");
v.play(); // returns a Promise
v.pause();
v.currentTime = 30; // seek to 0:30
v.muted = true;
v.addEventListener("ended", () => console.log("done"));
v.addEventListener("timeupdate", () => console.log(v.currentTime));Handle the Promise from play() — it rejects when the browser blocks playback.
Lazy loading and performance
preload="none"or"metadata"keeps the initial page light.- A
posterimage shows instantly. - Use
loading="lazy"on iframes; for <video>, set the src when it scrolls into view. - Reserve space with
aspect-ratioto avoid layout shift.
Accessibility checklist
- Add captions with <track kind="captions">.
- Keep
controlsunless you provide your own accessible controls. - Never autoplay with sound.
- Provide a transcript for important videos.
Common problems
- Video doesn’t play on iPhone
Add playsinline and muted for autoplay; check the codec is H.264.
- Black screen before play
Add a poster image.
- Wrong size on mobile
Use width:100%; height:auto; aspect-ratio.
- Large file loads slowly
Compress it or stream it from a video platform.
How the browser picks a source
The browser reads the <source> elements from top to bottom and plays the first one it supports. That’s why you list the smaller, more modern format first (WebM) and the universally supported one (MP4) second. The type attribute lets the browser skip files it can’t play without downloading them — always include it. Text placed inside <video> after the sources is shown only by browsers that don’t support video at all.
<video controls preload="metadata" poster="poster.jpg"> <source src="clip.webm" type='video/webm; codecs="vp9, opus"'> <source src="clip.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'> <a href="clip.mp4">Download the video</a> </video>
Fit video into any layout
Use CSS to control how the video fills its box. object-fit: cover fills the area and crops the edges — ideal for hero sections. object-fit: contain shows the whole frame with bars. Combine it with aspect-ratio to reserve space before the file loads and prevent layout shift.
.video-box{aspect-ratio:16/9;width:100%}
.video-box video{width:100%;height:100%;object-fit:cover}
/* vertical clips */
.video-vertical{aspect-ratio:9/16;max-width:360px}Picture-in-picture and fullscreen
Modern browsers let you move a video into a floating window or fullscreen from JavaScript — both need a user gesture such as a click.
const v = document.querySelector("video");
pipButton.onclick = async () => {
if (document.pictureInPictureElement) await document.exitPictureInPicture();
else await v.requestPictureInPicture();
};
fullButton.onclick = () => v.requestFullscreen();Add disablepictureinpicture to the element if you don’t want the browser’s own PiP button.
Track video engagement
The video element fires events you can send to your analytics tool. Track starts, completions and progress milestones — not every timeupdate, which fires several times per second.
const v = document.querySelector("video");
const sent = new Set();
const track = (name) => window.gtag && gtag("event", name, { video_title: v.dataset.title });
v.addEventListener("play", () => track("video_start"), { once: true });
v.addEventListener("ended", () => track("video_complete"));
v.addEventListener("timeupdate", () => {
const p = Math.floor((v.currentTime / v.duration) * 4) * 25; // 25, 50, 75
if (p && p < 100 && !sent.has(p)) { sent.add(p); track("video_progress_" + p); }
});Video tag, iframe or gallery?
The video tag is the right tool for your own short files: product loops, hero backgrounds, short explainers you host on a CDN. For videos on YouTube or Vimeo, use their iframe players — they handle streaming, quality switching and captions. When you need many videos, feeds that update themselves, or a mix of platforms, a gallery widget saves you from building playlists, popups and layouts by hand.
Frequently asked questions
How do I embed a video in HTML?
Use <video controls> with a <source> pointing to an MP4 file.
Why doesn’t autoplay work on my video tag?
Add muted (and playsinline for iPhone).
Can I play YouTube videos with the video tag?
No. Use the YouTube iframe embed.
What is the poster attribute?
An image shown before the video plays.
Can I use the video tag for YouTube?
No — YouTube needs its iframe player.
Which is better, MP4 or WebM?
MP4 (H.264) works everywhere; WebM is often smaller. Offer both, WebM first.
How do I stop the video from downloading on page load?
Use preload="none" or "metadata" and a poster image.
What does playsinline do?
On iPhone it keeps the video inside the page instead of switching to fullscreen. It’s required for inline autoplay.
How do I make a video loop only part of the clip?
Listen to timeupdate and set currentTime back to your start point when it passes the end point — or export the section as its own file.
Can I play a video from Google Drive in the video tag?
Not reliably. Drive share links open Drive’s viewer, not the file. Host the MP4 on your server, a CDN or cloud storage with a direct link.
How do I add chapters?
Add a <track kind="chapters"> with a WebVTT file; support for showing chapters varies by browser, so many sites also list chapters as buttons that set currentTime.