How do you programmatically play, pause, and dynamically set a video source?

Your grasp of HTMLMediaElement's imperative API and the play() Promise. Query the video, attach play() and pause() to buttons, and set src or swap source children then call load(). Treating play() as synchronous or changing src without load().
What's really being asked
This question evaluates whether you treat the DOM as a programmable API rather than static markup. Senior engineers should know that HTMLMediaElement defines the shared contract for both audio and video, that play() returns a Promise because browsers gate playback on user activation and autoplay policies, and that changing a media resource requires more than flipping a string property. It also checks if you understand the distinction between the element-level src attribute and nested source children, which matters for adaptive media or codec fallback strategies.
The full answer
First, element acquisition: use a typed ref in React or querySelector in vanilla TS, narrowing to HTMLVideoElement. Second, event wiring: attach click listeners to the play and pause buttons that call video.play() and video.pause(). Third, the Promise: acknowledge that play() is asynchronous and can reject with a NotAllowedError if the user has not interacted with the document, so robust code awaits or catches it. Fourth, dynamic source assignment: explain two valid paths. You can set video.src to a URL string and then call video.load() to reset the media controller and begin fetching. Alternatively, you can remove existing source children, create a new HTMLSourceElement, set its src and type attributes, append it to the video, and then call load(). Mention that load() is necessary to trigger resource selection when you manipulate source children.
The mistakes people make
Treating play() as a fire-and-forget synchronous call and ignoring the returned Promise. Setting video.src without calling load() and expecting the browser to immediately switch streams. Using innerHTML to inject a source tag and expecting the media element to pick it up without a load call. Confusing the element src property with the currentSrc property, which reflects the resolved resource after the browser has evaluated source children. Failing to type the element as HTMLVideoElement and instead using generic HTMLElement, which loses access to media-specific methods in TypeScript.
What usually comes next
How would you handle a user clicking play before the metadata has loaded? What happens if the browser blocks autoplay and the Promise rejects? How do you support multiple codecs or adaptive bitrate via source children versus a single src string? If you are in a framework like React, why is a ref preferable to an id or querySelector? How would you clean up event listeners or abort a pending load when the component unmounts?
A concrete example
In TypeScript, you might write const video = document.querySelector('video') as HTMLVideoElement; const playBtn = document.getElementById('play')!; const pauseBtn = document.getElementById('pause')!; playBtn.addEventListener('click', () => { video.play().catch(err => console.error('Playback failed:', err)); }); pauseBtn.addEventListener('click', () => { video.pause(); }); To change the source dynamically, you set video.src = 'new-video.mp4'; video.load(); and then optionally call play() again once the user clicks. If you prefer source elements, you clear video.innerHTML = ''; create a const source = document.createElement('source'); source.src = 'new-video.mp4'; source.type = 'video/mp4'; video.appendChild(source); video.load();.
Interview question
When programmatically changing a video element's source to a new URL, which approach correctly ensures the browser loads the new media?
- a.Insert a new source tag via innerHTML and rely on the DOM mutation to auto-load
- b.Assign the new URL to video.currentSrc and wait for the load event
- c.Assign the new URL to video.src and then call video.load()Correct
- d.Assign the new URL to video.src and immediately call video.play()
Why? this is the answer
Setting video.src only updates the resource URL; video.load() is required to reset the media controller and begin fetching the new stream. Option D omits the necessary load() call, while option B incorrectly treats currentSrc as writable and option A assumes innerHTML mutations trigger resource selection automatically.
Just read this? Test yourself on what you have been reading.
Read the original → developer.mozilla.org
- #typescript
- #htmlmediaelement
- #dom
- #web-apis
- #video
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on typescript — each one lists the topics its interview covers.
See open roles