Creating a Video Custom Controls using HTML, CSS, and JS Tutorial

In this tutorial, you can learn to create Video Custom Controls using HTML, CSS, and Pure JavaScript. The tutorial aims to provide students and beginners with a reference for learning the JS Web Video API to control the video element. Here, I will be providing simple web page scripts that demonstrate the creation of custom control of the video element.

What are Custom Video Custom Controls?

Basically, the HTML Video element has built-in controls for the video by adding a controls attribute to the element. Custom Video Controls are custom controls that the developer implemented to provide the end-users with more interactive and useful controls that are relevant only to the website.

How to Create a Custom Video Custom Controls?

Custom Video Custom Controls can be achieved simply by using HTML, CSS, and JavaScript. We can simply create the controls using some HTML elements such as div tags and design them using some CSS properties on how we prefer the controls should be looking. Then, using the JS Web Video API methods, we can add some event listeners to the controls we created and manage the video such as playing or pausing the video, changing the video's current play time, changing video volume, and more. Check out the source code scripts that I created and provided below to understand it more.

Sample Web Page Scripts

The following scripts result in a simple web page that contains a video element and custom controls. The custom controls contain a duration slider, volume, slider, backward (-10s) button, forward (+10s), play/pause button, current time text, and remain time text.

Page Interface

Here's the HTML file script known as index.html. The file contains the page layout, video, and custom controls elements. Please don't forget to change the video tag element source path with a video path that is available on your end.

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <meta charset="UTF-8">
  4. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  5. <title>Video Custom Control</title>
  6. <link rel="stylesheet" href="style.css">
  7. <link rel="preconnect" href="https://fonts.googleapis.com">
  8. <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  9. <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,[email protected],100..700,0..1,-50..200" />
  10. </head>
  11. <div class="container">
  12. <h1 id="page-title">Video Custom Control using HTML, CSS, and JS</h1>
  13. <hr id="title_hr">
  14. <div id="vid-wrapper">
  15. <video src="./demo_video.mp4"></video>
  16. <div id="custom-controls">
  17. <div id="vid-slider">
  18. <span id="current-time">00:00</span>
  19. <span id="vid-slider-holder">
  20. <input type="range" step="any" min="0" max="100" id="vid_duration" value="0">
  21. </span>
  22. <span id="remaining-time">00:00</span>
  23. </div>
  24. <div class="other-ctrls">
  25. <div class="btns">
  26. <div id="minus-10-sec-btn" title="10s Backward"><span class="material-symbols-outlined">undo</span></div>
  27. <div id="pause-play-btn" title="Play"><span class="material-symbols-outlined">play_arrow</span></div>
  28. <div id="plus-10-sec-btn" title="10s Forward"><span class="material-symbols-outlined">redo</span></div>
  29. </div>
  30. <div id="vol-slider-holder">
  31. <span class="material-symbols-outlined">volume_up</span>
  32. <input type="range" step="any" min="0" max="10" value="10" id="vol-slider">
  33. </div>
  34. </div>
  35. </div>
  36. </div>
  37. </div>
  38.  
  39. <script src="script.js"></script>
  40. </body>
  41. </html>

Stylesheet (CSS)

Next, here's the CSS file script known as style.css. The file contains the page layout and custom controls elements design or stylesheet codes.

  1. @import url('https://fonts.googleapis.com/css2?family=Dongle:wght@300;400;700&family=Roboto+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;1,100;1,200;1,300;1,400;1,500;1,600&display=swap" rel="stylesheet');
  2. *{
  3. margin: 0;
  4. padding: 0;
  5. box-sizing: border-box;
  6. font-family: 'Dongle', sans-serif;
  7. font-family: 'Roboto Mono', monospace;
  8. }
  9. ::selection{
  10. color: #fff;
  11. background: #4db2ec;
  12. }
  13. body{
  14. display: flex;
  15. align-items: center;
  16. justify-content: center;
  17. min-height: 100vh;
  18. background: #4facfe;
  19. background-image: linear-gradient(to right, #4facfe 0%, #00f2fe 100%);
  20. padding: 2em 0;
  21. }
  22. #page-title{
  23. color: #fff;
  24. text-align: center;
  25. font-weight: 500;
  26. text-shadow: 0px 0px 15px #0000003a;
  27. }
  28. #title_hr{
  29. width:60px;
  30. border: 2px solid #ffffff;
  31. margin: .35em auto;
  32. }
  33. @media (min-width: 780px){
  34. #page-title{
  35. width: 780px;
  36. }
  37. }
  38. /* Table Wrapper */
  39. #vid-wrapper{
  40. width: 700px;
  41. background-color: #000;
  42. border: 1px solid #2e2e2e;
  43. padding: 1em .75em;
  44. margin: 1em auto;
  45. border-radius: 5px;
  46. box-shadow: 1px 1px 10px #00000046;
  47. }
  48. /* Video Element */
  49. #vid-wrapper video{
  50. width: 100%;
  51. height: 350px;
  52. object-fit: scale-down;
  53. object-position: center center;
  54. }
  55. /* Video Duration Slider */
  56. div#vid-slider {
  57. color: #fff;
  58. display: flex;
  59. width: 100%;
  60. justify-content: center;
  61. align-items: center;
  62. }
  63. span#current-time,
  64. span#remaining-time {
  65. display: block;
  66. flex-shrink: 1;
  67. }
  68. #vid-slider-holder{
  69. display: block;
  70. flex-grow: 1;
  71. padding: 0 .35em;
  72. }
  73. #vid-slider-holder input{
  74. width: 100%;
  75. }
  76. /* duration range */
  77. #vid-slider-holder input {
  78. -webkit-appearance: none;
  79. appearance: none;
  80. width: 100%;
  81. cursor: pointer;
  82. outline: none;
  83. border-radius: 15px;
  84. height: 6px;
  85. background: #645a5a;
  86. }
  87.  
  88. #vid-slider-holder input::-webkit-slider-thumb {
  89. -webkit-appearance: none;
  90. appearance: none;
  91. height: 15px;
  92. width: 15px;
  93. background-color: #eeeeee;
  94. border-radius: 50%;
  95. border: 1px solid #c2c1c1;
  96. transition: .2s ease-in-out;
  97. }
  98.  
  99. #vid-slider-holder input::-moz-range-thumb {
  100. height: 15px;
  101. width: 15px;
  102. background-color: #eeeeee;
  103. border-radius: 50%;
  104. border: none;
  105. box-shadow: 0px 0px 3px #000;
  106. transition: .2s ease-in-out;
  107. }
  108.  
  109. #vid-slider-holder input::-webkit-slider-thumb:hover {
  110. box-shadow: 0 0 0 10px #2aaaff10
  111. }
  112. #vid-slider-holder input:focus::-webkit-slider-thumb {
  113. box-shadow: 0 0 0 13px #2aaaff1a
  114. }
  115.  
  116. #vid-slider-holder input::-moz-range-thumb:hover {
  117. box-shadow: 0 0 0 10px #2aaaff10
  118. }
  119. #vid-slider-holder input:focus::-moz-range-thumb {
  120. box-shadow: 0 0 0 13px #2aaaff1a
  121. }
  122.  
  123. /* Btns and other controls */
  124. .other-ctrls {
  125. display: flex;
  126. width: 100%;
  127. color: #fff;
  128. align-items: center;
  129. justify-content:space-between;
  130. }
  131. .other-ctrls .btns{
  132. display: flex;
  133. align-items: center;
  134. justify-content:center;
  135. flex-shrink: 1;
  136. }
  137. div#minus-10-sec-btn,
  138. div#pause-play-btn,
  139. div#plus-10-sec-btn {
  140. width: 20px;
  141. height: 20px;
  142. margin: 0.35em 0.5em;
  143. cursor: pointer;
  144. }
  145. div#minus-10-sec-btn:hover>span,
  146. div#pause-play-btn:hover>span,
  147. div#plus-10-sec-btn:hover>span {
  148. color: #cccccc !important;
  149. }
  150.  
  151. /* Volume Slider */
  152. #vol-slider-holder{
  153. width: 150px;
  154. display: flex;
  155. align-items: center;
  156. justify-content: center;
  157. }
  158.  
  159. #vol-slider {
  160. -webkit-appearance: none;
  161. appearance: none;
  162. width: 100%;
  163. cursor: pointer;
  164. outline: none;
  165. border-radius: 15px;
  166. height: 6px;
  167. background: #645a5a;
  168. }
  169.  
  170. #vol-slider::-webkit-slider-thumb {
  171. -webkit-appearance: none;
  172. appearance: none;
  173. height: 15px;
  174. width: 15px;
  175. background-color: #eeeeee;
  176. border-radius: 50%;
  177. border: 1px solid #c2c1c1;
  178. transition: .2s ease-in-out;
  179. }
  180.  
  181. #vol-slider::-moz-range-thumb {
  182. height: 15px;
  183. width: 15px;
  184. background-color: #eeeeee;
  185. border-radius: 50%;
  186. border: none;
  187. box-shadow: 0px 0px 3px #000;
  188. transition: .2s ease-in-out;
  189. }
  190.  
  191. #vol-slider::-webkit-slider-thumb:hover {
  192. box-shadow: 0 0 0 10px #2aaaff10
  193. }
  194. #vol-slider:focus::-webkit-slider-thumb {
  195. box-shadow: 0 0 0 13px #2aaaff1a
  196. }
  197.  
  198. #vol-slider::-moz-range-thumb:hover {
  199. box-shadow: 0 0 0 10px #2aaaff10
  200. }
  201. #vol-slider:focus::-moz-range-thumb {
  202. box-shadow: 0 0 0 13px #2aaaff1a
  203. }

JavaScript

Finally, here's the JavaScript file script known as script.js. The file contains the JS codes that make the custom controls functional and control the video element.

  1. // Select Video Element
  2. const video = document.querySelector("#vid-wrapper video")
  3. // Select Duration Slider Element
  4. const durationSliderEl = document.querySelector("#vid-slider-holder input")
  5. // Select Volume Slider Element
  6. const volumeSliderEl = document.querySelector("#vol-slider")
  7. // Select Backward icon Element
  8. const backward = document.getElementById('minus-10-sec-btn')
  9. // Select Forward icon Element
  10. const forward = document.getElementById('plus-10-sec-btn')
  11. // Select Play/Pause icon Element
  12. const playPause = document.getElementById('pause-play-btn')
  13. // Select Current Time Text Element
  14. const vidCurrentTime = document.getElementById('current-time')
  15. // Select Remaining Time Text Element
  16. const vidRemainTime = document.getElementById('remaining-time')
  17. // for duration interval
  18. let durationInterval;
  19.  
  20. // Update duration slider fill color
  21. const durationSlider= () =>{
  22. // get progress
  23. const progress = (durationSliderEl.value / durationSliderEl.max) * 100;
  24.  
  25. // Update Fill Color depending to progress
  26. durationSliderEl.style.background = `linear-gradient(to right, #3aa8ff ${progress}%, #645a5a ${progress}%)`;
  27. }
  28. // Update volume slider fill color
  29. const volumeSlider = () => {
  30. // get progress
  31. const progress = (volumeSliderEl.value / volumeSliderEl.max) * 100;
  32.  
  33. // Update Fill Color depending to progress
  34. volumeSliderEl.style.background = `linear-gradient(to right, #3aa8ff ${progress}%, #645a5a ${progress}%)`;
  35. }
  36.  
  37. // Update Duration Slider, current time, and remaining time elements
  38. const updateDuration = () =>{
  39. // get current time
  40. var currentTime = video.currentTime
  41. // get video total duration
  42. var totalTime = video.duration
  43. // Compute Remaining Time
  44. var remain = totalTime - currentTime
  45. // Compute duration slider value
  46. var sliderValue = (currentTime / totalTime) * 100;
  47. // Reset Duration Slider Value
  48. durationSliderEl.value= sliderValue
  49. // update duration slider
  50. durationSlider()
  51. // compute Current Time (m:s)
  52. var curtimeMins = Math.floor(currentTime / 60)
  53. var curtimeSecs = Math.floor(((currentTime / 60) - curtimeMins) * 60)
  54. // compute Remaining Time (m:s)
  55. var remainTimeMins = Math.floor(remain / 60)
  56. var remainTimeSecs = Math.floor(((remain / 60) - remainTimeMins) * 60)
  57. // make current time minimum 2 digits and add 0 before the digit if only single digits
  58. curtimeMins = String(curtimeMins).padStart(2, 0);
  59. curtimeSecs = String(curtimeSecs).padStart(2, 0);
  60. // make remaining time minimum 2 digits and add 0 before the digit if only single digits
  61. remainTimeMins = String(remainTimeMins).padStart(2, 0);
  62. remainTimeSecs = String(remainTimeSecs).padStart(2, 0);
  63. // Update current Time Element Text
  64. vidCurrentTime.innerText = `${curtimeMins}:${curtimeSecs}`
  65. // Update remaining Time Element Text
  66. vidRemainTime.innerText = `${remainTimeMins}:${remainTimeSecs}`
  67. }
  68. window.onload = ()=>{
  69. volumeSlider()
  70. updateDuration()
  71. playPause.addEventListener('click', e=>{
  72. e.preventDefault()
  73. if(!!playPause.dataset.playing){
  74. delete playPause.dataset.playing;
  75. video.pause()
  76. playPause.innerHTML = `<span class="material-symbols-outlined">play_arrow</span>`
  77. }else{
  78. playPause.dataset.playing= 'true'
  79. video.play()
  80. playPause.innerHTML = `<span class="material-symbols-outlined">pause</span>`
  81. }
  82. })
  83. video.addEventListener('play', e => {
  84. durationInterval = setInterval(()=>{
  85. updateDuration()
  86. }, 100)
  87. })
  88. video.addEventListener('pause', e => {
  89. if(durationInterval != undefined){
  90. clearInterval(durationInterval)
  91. }
  92. })
  93. backward.addEventListener('click', e=>{
  94. e.preventDefault()
  95. var currentTime = video.currentTime
  96. currentTime -= 10;
  97. currentTime = (currentTime < 0) ? 0 : currentTime
  98. video.currentTime = currentTime
  99. updateDuration()
  100. })
  101. forward.addEventListener('click', e=>{
  102. e.preventDefault()
  103. var currentTime = video.currentTime
  104. currentTime += 10;
  105. currentTime = (currentTime > video.duration) ? video.duration : currentTime
  106. video.currentTime = currentTime
  107. updateDuration()
  108. })
  109. durationSliderEl.addEventListener("input", (event) => {
  110. durationSlider()
  111. var duration = video.duration
  112. var newCurrentTime = (durationSliderEl.value / 100) * duration
  113. video.currentTime = newCurrentTime
  114. updateDuration()
  115. })
  116. volumeSliderEl.addEventListener("input", (event) => {
  117. volumeSlider()
  118. var vol = (volumeSliderEl.value / 10)
  119. video.volume = vol
  120. })
  121. video.addEventListener("ended", e=>{
  122. delete playPause.dataset.playing;
  123. video.pause()
  124. playPause.innerHTML = `<span class="material-symbols-outlined">play_arrow</span>`
  125. video.currentTime = 0
  126. })
  127. }

Snapshots

Here are some snapshots of the overall result of the web page scripts I have provided.

Page UI

Custom Video Controls using HTML, CSS, and JS

Video and Custom Control Block

Custom Video Controls using HTML, CSS, and JS

Custom Controls

Custom Video Controls using HTML, CSS, and JS

Video Block when Playing

Custom Video Controls using HTML, CSS, and JS

There you go! I have also provided the complete source code zip file of the web page scripts on this website and it is free to download. The download button is located below this tutorial's content. Feel free to download and modify the source code the way you desire.

DEMO VIDEO

That's it! I hope this Creating a Video Custom Controls using HTML, CSS, and JS Tutorial will help you with what you are looking for and you'll find this useful for your current and future web application projects.

Explore more on this website for more Tutorials and Free Source Codes.

Happy Coding =)

Add new comment