About this snippet

Host your own videos using this modern HTML5 player. We included SVG controls and chapter markers, so you can easily guide users to the best parts of your content.

Size
4.1 KB
Uses
HTML, CSS, JavaScript
Loads
codeshack.io
Views
188
<div class="custom-video-player">
  <video id="main-video" src="https://codeshack.io/web/example.mp4" playsinline></video>
  
  <div class="player-controls">
    <button id="play-pause-btn" aria-label="Play">
      <svg class="play-icon" viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
        <polygon points="5 3 19 12 5 21 5 3"></polygon>
      </svg>
    </button>
    
    <div class="timeline-container" id="timeline">
      <div class="timeline-progress" id="progress"></div>
      <div class="chapter-marker" style="left: 25%" title="Intro"></div>
      <div class="chapter-marker" style="left: 50%" title="Main Feature"></div>
      <div class="chapter-marker" style="left: 80%" title="Conclusion"></div>
    </div>
    
    <span class="time-display" id="time-display">0:00</span>
  </div>
</div>
*, *::before, *::after {
  box-sizing: border-box;
}

body {
  font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  background: #f3f4f6;
  display: flex;
  justify-content: center;
  padding: 40px;
  margin: 0;
  min-height: 100vh;
  align-items: center;
}

.custom-video-player {
  position: relative;
  width: 100%;
  max-width: 800px;
  border-radius: 16px;
  overflow: hidden;
  background: #000000;
  box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
}

#main-video {
  width: 100%;
  display: block;
}

.player-controls {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
  padding: 20px;
  display: flex;
  align-items: center;
  gap: 16px;
  opacity: 0;
  transition: opacity 0.3s;
}

.custom-video-player:hover .player-controls {
  opacity: 1;
}

#play-pause-btn {
  background: none;
  border: none;
  color: #ffffff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: color 0.2s;
}

#play-pause-btn:hover {
  color: #3b82f6;
}

.timeline-container {
  flex-grow: 1;
  height: 6px;
  background: rgba(255, 255, 255, 0.3);
  border-radius: 3px;
  position: relative;
  cursor: pointer;
}

.timeline-progress {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background: #3b82f6;
  border-radius: 3px;
  width: 0%;
  pointer-events: none;
}

.chapter-marker {
  position: absolute;
  top: -3px;
  width: 4px;
  height: 12px;
  background: #ffffff;
  border-radius: 2px;
  transition: transform 0.2s;
}

.chapter-marker:hover {
  transform: scale(1.5);
}

.chapter-marker:hover::after {
  content: attr(title);
  position: absolute;
  top: -30px;
  left: 50%;
  transform: translateX(-50%) scale(0.66);
  background: #111827;
  color: #ffffff;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 0.75rem;
  white-space: nowrap;
}

.time-display {
  color: #ffffff;
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
}
const video = document.getElementById("main-video");
const playBtn = document.getElementById("play-pause-btn");
const timeline = document.getElementById("timeline");
const progress = document.getElementById("progress");
const timeDisplay = document.getElementById("time-display");

playBtn.addEventListener("click", () => {
  if (video.paused) {
    video.play();
    playBtn.innerHTML = `<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><rect x="6" y="4" width="4" height="16"></rect><rect x="14" y="4" width="4" height="16"></rect></svg>`;
  } else {
    video.pause();
    playBtn.innerHTML = `<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>`;
  }
});

video.addEventListener("timeupdate", () => {
  const pct = (video.currentTime / video.duration) * 100;
  progress.style.width = pct + "%";
  
  const mins = Math.floor(video.currentTime / 60);
  const secs = Math.floor(video.currentTime % 60).toString().padStart(2, "0");
  timeDisplay.textContent = mins + ":" + secs;
});

timeline.addEventListener("click", (e) => {
  const rect = timeline.getBoundingClientRect();
  const clickPos = (e.clientX - rect.left) / rect.width;
  video.currentTime = clickPos * video.duration;
});
Esc
↑↓ moveEnter select

Start from a template

Open an .html file, or HTML, CSS, JS, Markdown, Less or TypeScript files. You can also drop them here. Styles and scripts go into their panes.

Share

Source

Keyboard shortcuts

Save