πΊ What is the YouTube IFrame API?
The YouTube IFrame Player API lets you embed and control YouTube videos using JavaScript. Unlike the standard embed method (which only gives you a video player), the IFrame API allows programmatic control over playback, volume, seeking, and more β directly in your web app.
π Key Features of the IFrame API
- Embed YouTube videos dynamically using JavaScript
- Control playback: play, pause, stop, seek
- Listen to player events (e.g., ready, playing, paused, ended)
- Customize player UI or hide it completely
- Works cross-platform using an under the hood
β 1. Setup
'use client';
import { useEffect, useRef, useState } from 'react'
- use client enables React client-side interactivity in Next.js App Router.
- useState and useRef are used to manage state and player references.
β 2. State and Refs
const playerRef = useRef<any>(null); // reference to YT player
const seekRef = useRef<any>(null); // reference to the seek slider
const intervalRef = useRef<any>(null); // to store the interval for updating time
const [duration, setDuration] = useState(0);
const [currentTime, setCurrentTime] = useState(0);
const [volume, setVolume] = useState(50);
const [isPlaying, setIsPlaying] = useState(false);
const [isPlayerReady, setIsPlayerReady] = useState(false);
- duration, currentTime: Track progress.
- volume: Stores volume level.
- isPlaying: Toggles icon and playback.
- isPlayerReady: Disables controls until API is ready.
β 3. Load and Initialize YouTube Player API
useEffect(() => {
const tag = document.createElement('script');
tag.src = 'https://www.youtube.com/iframe_api';
document.body.appendChild(tag);
if (!window.YT) {
window.onYouTubeIframeAPIReady = initPlayer;
} else {
initPlayer();
}
return () => {
if (intervalRef.current) clearInterval(intervalRef.current);
};
}, []);
Dynamically loads the YouTube IFrame API.
Initializes player only once, and cleans up the interval on unmount.
β 4. Initialize Player
const initPlayer = () => {
playerRef.current = new window.YT.Player('yt-player', {
videoId: 'M7lc1UVf-VE',
playerVars: { controls: 0, playsinline: 1 },
events: {
onReady: onPlayerReady,
onStateChange: (e) => {
setIsPlaying(e.data === window.YT.PlayerState.PLAYING);
},
},
});
};
- Creates the YouTube player hidden in the DOM.
- Disables default controls and tracks player state.
β 5. Handle Player Ready Event
const onPlayerReady = () => {
playerRef.current.setVolume(volume);
setDuration(playerRef.current.getDuration());
setIsPlayerReady(true);
intervalRef.current = setInterval(() => {
const current = playerRef.current.getCurrentTime();
setCurrentTime(current);
if (seekRef.current && duration > 0) {
seekRef.current.value = ((current / duration) * 100).toString();
}
}, 1000);
};
- Sets default volume.
- Gets video duration.
- Updates seek bar every second using setInterval.
β 6. Playback Toggle
const togglePlayback = () => {
if (!isPlayerReady) return;
if (isPlaying) {
playerRef.current.pauseVideo();
} else {
playerRef.current.playVideo();
}
};
- Plays or pauses audio based on the current isPlaying state.
β 7. Format Time
const formatTime = (seconds: number) => {
const min = Math.floor(seconds / 60);
const sec = Math.floor(seconds % 60);
return `${min}:${sec < 10 ? '0' + sec : sec}`;
};
- Converts seconds into mm:ss format for display under the seek bar.
β 8. Render UI
<div className="bg-[#E7E7E7] p-4 rounded-xl w-full mx-auto shadow">
<div id="yt-player" className="hidden" />
- Hidden YouTube player is injected here.
- UI container is styled using Tailwind CSS.
β 9. Controls: Play/Pause Button
<button
onClick={togglePlayback}
disabled={!isPlayerReady}
className={`w-20 h-14 rounded-[32px] text-white text-2xl ${
isPlayerReady ? 'bg-green-700 hover:bg-green-800' : 'bg-gray-400 cursor-not-allowed'
}`}
>
{isPlaying ? 'βΈ' : 'βΆ'}
</button>
- Dynamically switches icon and color.
- Disabled until the player is ready.
β 10. Seek Bar & Timestamps
<input
type="range"
ref={seekRef}
min="0"
max="100"
onChange={(e) => {
const time = (parseFloat(e.target.value) / 100) * duration;
playerRef.current.seekTo(time, true);
}}
disabled={!isPlayerReady}
className="flex-grow h-4 rounded bg-gray-300 accent-[#001947]"
/>
- Displays and updates the progress.
- Seekable after the player is ready.
β 11. Volume Control
<input
type="range"
min="0"
max="100"
value={volume}
disabled={!isPlayerReady}
onChange={(e) => {
const val = Number(e.target.value);
setVolume(val);
playerRef.current.setVolume(val);
}}
className="w-20 h-1 cursor-pointer accent-[#6D6D6D]"
/>
- Controls audio volume.
- Synced with the internal YT player state.
Top comments (0)