Custom native HTML, CSS and JS video player. Completely native no library is needed. Colors can be changed from CSS easily.
Enjoy using. Alternative ->
See the Pen Untitled by sinanisler (@sinanisler) on CodePen.
<div class="video-container"> <video id="myVideo"> <source src="https://wpaimuse.com/wp-content/uploads/2024/03/2024-03-14-11-59-41-2.mp4" type="video/mp4"> Your browser does not support the video tag. </video> <!-- Custom Controls --> <div class="controls"> <button id="playPauseBtn">►</button> <div class="progress-container"> <div id="progressBar" class="progress-bar"> <div id="progress" class="progress"></div> <!-- Progress dots will be added here --> </div> </div> <button id="muteBtn">🔈</button> <button id="fullscreenBtn">⛶</button> </div> <!-- Chapter buttons --> <div id="chapterButtons" class="chapter-buttons" style="display:none"></div> </div>
/* Container styling */ .video-container { position: relative; width: 640px; margin: 0 auto; background: #000; } /* Video styling */ #myVideo { width: 100%; } /* Custom controls styling */ .controls { display: flex; align-items: center; justify-content: space-between; background: #333; padding: 10px; color: #fff; } .controls button { background: none; border: none; color: #fff; font-size: 20px; cursor: pointer; } /* Progress bar container */ .progress-container { flex: 1; margin: 0 10px; position: relative; height: 10px; background: #555; cursor: pointer; } /* Progress bar */ .progress-bar { position: relative; width: 100%; height: 100%; } .progress { background: #2196F3; height: 100%; width: 0%; } /* Progress dots */ .progress-dot { position: absolute; top: 50%; width: 8px; height: 8px; background: #fff; border-radius: 50%; cursor: pointer; transform: translate(-50%, -50%); } /* Tooltip styling */ .tooltip { position: absolute; padding: 5px 10px; background: rgba(0, 0, 0, 0.8); color: #fff; border-radius: 4px; font-size: 14px; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 0.2s; } /* Chapter buttons styling */ .chapter-buttons { margin-top: 20px; text-align: center; } .chapter-buttons button { margin: 5px; padding: 10px; font-size: 16px; cursor: pointer; }
// Get the video element const video = document.getElementById('myVideo'); // Array of chapters with title and time (in minutes:seconds) const chapters = [ { title: "Chapter 1", time: "0:30" }, { title: "Chapter 2", time: "1:00" }, { title: "Chapter 3", time: "1:30" }, { title: "Chapter 4", time: "2:00" } ]; // Convert "min:sec" to total seconds function timeToSeconds(time) { const [minutes, seconds] = time.split(':').map(Number); return minutes * 60 + seconds; } // Jump to a specific time in the video function goToTime(seconds) { video.currentTime = seconds; video.play(); } // Generate chapter buttons const chapterButtonsDiv = document.getElementById('chapterButtons'); chapters.forEach((chapter) => { const button = document.createElement('button'); button.textContent = `${chapter.title} - ${chapter.time}`; button.addEventListener('click', () => { const seconds = timeToSeconds(chapter.time); goToTime(seconds); }); chapterButtonsDiv.appendChild(button); }); // Custom Controls const playPauseBtn = document.getElementById('playPauseBtn'); const muteBtn = document.getElementById('muteBtn'); const fullscreenBtn = document.getElementById('fullscreenBtn'); const progressContainer = document.querySelector('.progress-container'); const progressBar = document.getElementById('progress'); const progressBarContainer = document.getElementById('progressBar'); // Tooltip element const tooltip = document.createElement('div'); tooltip.className = 'tooltip'; document.body.appendChild(tooltip); // Play/Pause functionality playPauseBtn.addEventListener('click', () => { if (video.paused) { video.play(); playPauseBtn.textContent = '❚❚'; } else { video.pause(); playPauseBtn.textContent = '►'; } }); // Mute/Unmute functionality function updateMuteButton() { muteBtn.textContent = video.muted ? '🔈+' : '🔈-'; } // Initial mute button state updateMuteButton(); muteBtn.addEventListener('click', () => { video.muted = !video.muted; updateMuteButton(); }); // Fullscreen functionality fullscreenBtn.addEventListener('click', () => { if (video.requestFullscreen) { video.requestFullscreen(); } else if (video.webkitRequestFullscreen) { /* Safari */ video.webkitRequestFullscreen(); } else if (video.msRequestFullscreen) { /* IE11 */ video.msRequestFullscreen(); } }); // Update progress bar as the video plays video.addEventListener('timeupdate', () => { const percent = (video.currentTime / video.duration) * 100; progressBar.style.width = percent + '%'; }); // Seek functionality progressContainer.addEventListener('click', (e) => { const rect = progressContainer.getBoundingClientRect(); const offsetX = e.clientX - rect.left; const totalWidth = rect.width; const percent = offsetX / totalWidth; video.currentTime = percent * video.duration; }); // Create progress dots after metadata is loaded function createProgressDots() { chapters.forEach((chapter) => { const dot = document.createElement('div'); dot.classList.add('progress-dot'); const seconds = timeToSeconds(chapter.time); const percent = (seconds / video.duration) * 100; dot.style.left = percent + '%'; // Store the chapter title for tooltip dot.dataset.title = chapter.title; // Add event listeners for tooltip dot.addEventListener('mouseenter', (e) => { tooltip.textContent = chapter.title; tooltip.style.opacity = 1; const rect = dot.getBoundingClientRect(); tooltip.style.left = rect.left + 'px'; tooltip.style.top = rect.top - 30 + 'px'; // Position above the dot }); dot.addEventListener('mouseleave', () => { tooltip.style.opacity = 0; }); dot.addEventListener('click', (e) => { e.stopPropagation(); // Prevent triggering the parent click event goToTime(seconds); }); progressBarContainer.appendChild(dot); }); } // Wait for video metadata to be loaded before creating progress dots if (video.readyState >= 1) { createProgressDots(); } else { video.addEventListener('loadedmetadata', createProgressDots); } // Update Play/Pause button text based on video state video.addEventListener('play', () => { playPauseBtn.textContent = '❚❚'; }); video.addEventListener('pause', () => { playPauseBtn.textContent = '►'; }); // Update mute button when video mute state changes video.addEventListener('volumechange', updateMuteButton);