HTML Source Element
So far, you have pointed <audio> and <video> at one file. That works until a visitor's browser cannot play that format. The <source> element solves this: it lets you list several files of the same media, and the browser picks the first one it can play.
Think of it like giving a traveller several train tickets for the same trip. They use the first one that matches a train that is actually running.
What You Will Learnβ
- Putting
<source>elements inside<audio>and<video> - The
src,type, andmediaattributes - How the browser chooses, and why order matters
- Writing
typewith codecs - Fallback content when nothing plays
- Mistakes that waste data or break playback
The Basicsβ
- HTML Code
- How the Browser Chooses
<video controls width="640" height="360" poster="cover.jpg">
<source src="lesson.webm" type="video/webm">
<source src="lesson.mp4" type="video/mp4">
<p>
Your browser cannot play this video.
<a href="lesson.mp4">Download the MP4</a>.
</p>
</video>
<audio controls>
<source src="episode.opus" type="audio/ogg; codecs=opus">
<source src="episode.mp3" type="audio/mpeg">
Your browser cannot play this audio.
<a href="episode.mp3">Download the MP3</a>.
</audio>
clip-av1.mp4β skippedclip.webmβ chosenclip.mp4(playable, but an earlier one was chosen)
The browser plays clip.webm.
The browser walks down the list, in order. For each <source>, it asks: "Can I play this type?" The first "yes" wins. The rest are never downloaded. If every answer is "no", it shows the text inside the element instead.
Try the simulator above: tick the formats your imaginary browser supports, and move the files up and down.
The Rulesβ
| Rule | Detail |
|---|---|
source is a void element | No closing tag, and no content |
It must be a child of audio, video, or picture | Anywhere else, it does nothing |
| Put it before any fallback text | Fallback comes last |
Do not also set src on the parent | If the parent has a src, the source children are ignored |
| Order matters | The first playable source wins |
Each needs src | A source with no src is skipped |
Each should have type | So the browser can skip it without downloading |
Attributesβ
srcβ
The address of the file, just as on the parent element. Relative paths and full URLs both work.
typeβ
The MIME type of the file, and optionally its codecs. It lets the browser reject a file before downloading it.
<source src="clip.mp4" type="video/mp4">
<source src="clip.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
<source src="clip.webm" type='video/webm; codecs="vp9, opus"'>
<source src="clip.ogg" type="audio/ogg; codecs=opus">
Why codecs? A file such as .mp4 is just a container. Inside, the video and audio can be compressed in different ways (codecs). A browser might open an MP4 container but not understand the codec inside. Adding codecs lets it decide correctly, but a wrong codec string causes a good file to be skipped, so copy it carefully.
Common MIME types:
| File | type |
|---|---|
.mp4 (video) | video/mp4 |
.webm (video) | video/webm |
.ogv | video/ogg |
.mp3 | audio/mpeg |
.m4a (AAC) | audio/mp4 |
.ogg, .opus | audio/ogg |
.wav | audio/wav |
.flac | audio/flac |
Also make sure your server sends the correct Content-Type header for each file. A correct type in HTML does not help if the server says something else, and some browsers refuse to play.
mediaβ
A media query that must match for the source to be used (on video and audio, support is limited and uneven, so treat it as an optional extra and always test).
<video controls>
<source src="clip-small.mp4" type="video/mp4" media="(max-width: 600px)">
<source src="clip-large.mp4" type="video/mp4">
</video>
Do not rely on media to save data on phones. It is not widely supported for media, and the browser may ignore it. A more dependable approach is to serve one reasonably sized file, or choose the file with JavaScript.
source inside picture is differentOn a <picture> element, source uses srcset, sizes, type, and media, and has no src. Do not mix the two. This lesson covers source inside audio and video.
Try It: Watch a Real Browser Chooseβ
This demo is a real <audio> with real <source> children. Rearrange them and see which one is used. The page reads the element's currentSrc property to find out.
- HTML Code
- Browser Output
<audio id="player" controls>
<source src="a.xyz" type="audio/x-unsupported">
<source src="b.wav" type="audio/wav">
</audio>
<p id="result"></p>
const player = document.getElementById("player");
player.addEventListener("loadedmetadata", () => {
// currentSrc is the source the browser actually picked
document.getElementById("result").textContent = "Playing: " + player.currentSrc;
});
Preparing the soundsβ¦
The browser chose: (waiting for the browser to chooseβ¦)
<audio controls>
<source src="a.xyz" type="audio/x-unsupported">
<source src="b.wav" type="audio/wav">
</audio>
This is a real audio element with real source children. A wrong type is skipped at once, and a file that fails to load makes the browser move on to the next source (most browsers do this, but the exact behaviour can differ).
Choosing the Orderβ
Put your sources in order of preference, from best to most widely supported:
- The smallest or best-quality format first (for example WebM or AV1).
- The safest, most compatible format last (MP4 with H.264 and AAC, or MP3 for audio).
The browser takes the first it can play, so a modern browser gets the efficient file, and an older one falls through to the safe one. For many sites, a single MP4 or MP3 is enough, and a single file is simpler to maintain. Add more formats only when they save real data for your visitors.
Encoding every video three times means three files to store, test, and update. Offer a second format only if it makes a clear difference, for example a WebM that is a third smaller.
Fallback Contentβ
The text and elements after the last <source> are shown only if nothing can be played, or if the browser does not know <video> at all.
<video controls>
<source src="clip.webm" type="video/webm">
<source src="clip.mp4" type="video/mp4">
<p>Your browser cannot play this video. <a href="clip.mp4">Download it (MP4, 18 MB)</a>.</p>
</video>
A download link with the file type and size is the most useful fallback. It also helps people on connections too slow to stream.
Changing Sources with JavaScriptβ
If you change the src of a <source> after the page loads, the browser does not notice. Call load() to make it look again:
const video = document.querySelector("video");
video.querySelector("source").src = "other-lesson.mp4";
video.load(); // re-run the selection
video.play();
Handy properties:
video.currentSrc: the address of the source actually chosen.video.canPlayType(type): ask whether a type is playable ("probably","maybe", or""). See the overview.- The
errorevent fires on eachsourceelement that fails, and on the last one when all fail. It does not fire on the parentvideo.
const sources = document.querySelectorAll("video source");
const last = sources[sources.length - 1];
last.addEventListener("error", () => {
console.log("No source could be played. Show a download link.");
});
Accessibility at a Glanceβ
- Every source should hold the same content. A WebM with captions and an MP4 without them leaves some visitors behind.
- Captions belong to the parent, through
<track>, and work with whichever source is chosen. - Always give fallback content with a text alternative or a download link.
- Keep the same quality of audio in every format, so some visitors do not get a worse experience.
- Do not hide information in one format. Chapters, narration, and description should match in all of them.
Security and Privacy Notesβ
- Every listed file is public. Anyone can read your HTML and fetch each URL. Do not leave private test files or unreleased versions listed as sources.
- Serve all files over HTTPS, or the browser may block them as mixed content.
- Send correct
Content-Typeheaders, and addX-Content-Type-Options: nosniffon the server, so a file cannot be mistaken for something else. - Do not build
srcvalues from untrusted input, such as a URL typed by a visitor. It can point to a harmful or private address. Allow only addresses you control. - Third-party hosts (CDNs, video platforms) can see which files your visitors fetch. Check their privacy terms.
Global Audience Notesβ
- Fewer, smaller files help visitors on slow or expensive connections. Do not make people download three formats. The browser downloads only one, but your server stores all of them.
- Offer the format that saves data first, and a universal one last.
- Name files plainly, using lowercase letters, digits, and hyphens. Non-English file names can break in links and servers that handle encoding differently.
- Show the file type and size in download links (in the page's language), so visitors can decide before they download.
- Test on the browsers your audience really uses, including older phones. Format support varies by device and over time.
Common Mistakes to Avoidβ
- Setting
srconvideoand also addingsourcechildren. The children are ignored. - Leaving out
type, so the browser downloads files it cannot play. - A wrong codec string, so a good file is skipped.
- Putting the safest format first, so modern browsers never get the smaller one.
- Putting fallback text before the sources.
- No fallback content or download link.
- Changing a
sourcewith JavaScript and forgettingload(). - Listening for
erroron thevideoinstead of the lastsource. - Wrong server
Content-Type. - Different captions or content in different formats.
- Offering too many formats, with more to maintain and no real benefit.
- Using
mediaon audio or video and expecting it to save mobile data.
Practice Timeβ
Try these in your editor, with a short clip in two formats:
- Add two
sourceelements to avideo, MP4 last. - Open the network panel, and check that only one file downloads.
- Remove the
typeattributes, and compare what is requested. - Put an invalid
typefirst, and see which file is used. - Add fallback text with a download link, and view it by using an unsupported type for every source.
- Print
video.currentSrcafterloadedmetadata. - Switch the source with JavaScript, with and without
load(). - Listen for the
errorevent on the lastsource. - Run
canPlayType()for your two formats in the console. - Bonus: encode a WebM, compare its size with the MP4, and decide whether it is worth offering.
Quick Recapβ
Click a question to check your answer.
1. What does the source element do?
It lists one version of a media file inside audio or video. With several, the browser plays the first one it can handle.
2. Why add a type attribute?
It lets the browser skip files it cannot play without downloading them. Adding codecs makes the answer more exact, but a wrong codec string can wrongly skip a good file.
3. In what order should sources be listed?
From the best or smallest format to the most widely supported one, so modern browsers get the efficient file and older ones fall through to the safe one.
4. What happens if the parent also has a src attribute?
The source children are ignored. Use one approach or the other.
5. Where does the error event fire when no source works?
On the source elements, and the last one is the best place to listen. It does not fire on the parent video or audio.
6. How do you change the source with JavaScript?
Set the new src on the source element, then call load() on the parent so the browser runs its selection again.
Key Takeawaysβ
<source>lets one<audio>or<video>offer several files, and the browser plays the first it can handle.- Give each source a
type, with codecs when you are sure of them. - Order matters: efficient formats first, the safest last.
- Do not set
srcon the parent when you usesourcechildren. - End with fallback text and a download link.
- After changing a source with script, call
load(), and readcurrentSrcto see what was chosen. - Make sure every format has the same content, captions, and quality.
- Public files are public: do not list private files, and send correct headers.
Next, learn about the controls that come with media and how to build your own, in Media Controls, or return to the Audio and Video overview.