{"id":27761,"date":"2023-06-16T07:00:00","date_gmt":"2023-06-16T14:00:00","guid":{"rendered":"http:\/\/build-a-custom-html5-video-player-with-javascript"},"modified":"2025-10-10T15:05:44","modified_gmt":"2025-10-10T22:05:44","slug":"build-a-custom-html5-video-player-with-javascript","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript","title":{"rendered":"Build a Custom HTML5 Video Player With JavaScript"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>The HTML5 video player code specification was introduced via the <code>&lt;video&gt;<\/code> element, which can be used to embed video content into web pages, and it is well supported across modern browsers. In this post, you\u2019ll learn how to embed an HTML5 video player and define an HTML video custom controls that are independent of the browser defaults.<\/p>\n<p>There\u2019s a <a href=\"https:\/\/codesandbox.io\/s\/html5-video-player-with-css-and-javascript-6i7x6x\">link<\/a> to the demo in the CodeSandbox tool below so you can open it and play around on your own.<\/p>\n<\/div>\n\n\n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/html5-video-player-with-css-and-javascript-6i7x6x?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"html5-video-player-with-css-and-javascript-6i7x6x\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n\n<div class=\"wp-block-cloudinary-markdown \"><h2>Setting Up the Custom Video Player Project<\/h2>\n<p>Run the following command to create three files, <code>index.html<\/code>, <code>style.css<\/code>, and <code>script.js<\/code>, in a folder called <code>custom-video-player<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">mkdir<\/span> <span class=\"hljs-selector-tag\">custom-video-player<\/span>\n<span class=\"hljs-selector-tag\">cd<\/span> <span class=\"hljs-selector-tag\">custom-video-player<\/span>\n<span class=\"hljs-selector-tag\">touch<\/span> <span class=\"hljs-selector-tag\">index<\/span><span class=\"hljs-selector-class\">.html<\/span> <span class=\"hljs-selector-tag\">style<\/span><span class=\"hljs-selector-class\">.css<\/span> <span class=\"hljs-selector-tag\">script<\/span><span class=\"hljs-selector-class\">.js<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>To embed an HTML video player into our application, let\u2019s add the following to our <code>index.html<\/code> file:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-meta\">&lt;!DOCTYPE <span class=\"hljs-meta-keyword\">html<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">html<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"en\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">charset<\/span>=<span class=\"hljs-string\">\"UTF-8\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"viewport\"<\/span> <span class=\"hljs-attr\">content<\/span>=<span class=\"hljs-string\">\"width=device-width, initial-scale=1.0\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">title<\/span>&gt;<\/span>Custom HTML5 Video Player<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">title<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">link<\/span> <span class=\"hljs-attr\">rel<\/span>=<span class=\"hljs-string\">\"stylesheet\"<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"style.css\"<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>Video Player<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"video-player\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"video\"<\/span> <span class=\"hljs-attr\">controls<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">source<\/span>\n          <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/ifeomaimoh\/video\/upload\/v1650567487\/speech_ofvfzq.mp4\"<\/span>\n          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"video\/mp4\"<\/span>\n        \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">source<\/span>\n          <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/ifeomaimoh\/video\/upload\/v1650567487\/speech_ofvfzq.mp4\"<\/span>\n          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"video\/webm\"<\/span>\n        \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Your browser doesn't support HTML5 video.<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">video<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"script.js\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">html<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the code above, we rendered the <code>video&gt;<\/code> element. You can either add a video from your local computer to the <code>src<\/code> attribute or go with the default <a href=\"https:\/\/cloudinary.com\/\">Cloudinary<\/a> link used in the code. The HTML5 player specification currently supports three video formats, but we used multiple <code>&lt;source&gt;<\/code> tags to make two formats of the same video available in MP4 and WebM. In addition, we specified predefined content to be displayed for user agents that do not support the <code>video<\/code> element.<\/p>\n<p>The <code>video<\/code> tag also accepts several optional native attributes, such as <code>controls<\/code>, which display the standard HTML5 player controls interface when specified or set to true. Click <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/HTMLMediaElement#properties\">here<\/a> to find out more about other attributes.<\/p>\n<p>Before we continue, let\u2019s add some styles to give our app a decent look. Populate your <code>style.css<\/code> file with styles from this <a href=\"https:\/\/codesandbox.io\/s\/html5-video-player-with-css-and-javascript-6i7x6x?file=\/style.css\">CodeSandbox link<\/a>. If you preview the page in your browser, you should see the embedded video player as seen below:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_FD9C71930CCF880E72011A38A6294DD970A32CD4C820AFFF872B8729AD63F6C3_1651169673556_CleanShot+2022-04-28+at+22.14.14.gif\" alt=\"GIF image of video of the moon showing example html5 video player code in action\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"800\" height=\"363\"\/><\/p>\n<h2>Customizing the HTML5 Video Player<\/h2>\n<p>Before customizing the video player code, we need to remove the <code>controls<\/code> attribute, which displays video controls such as <code>Play<\/code>, <code>Pause<\/code>, etc., and then build our custom controls. Update the <code>&lt;video&gt;<\/code> element in your <code>index.html<\/code> file as shown below:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"video\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">source<\/span>\n    <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/ifeomaimoh\/video\/upload\/v1650352188\/production.mp4\"<\/span>\n    <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"video\/mp4\"<\/span>\n  \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">source<\/span>\n    <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/ifeomaimoh\/video\/upload\/v1650352188\/production.mp4\"<\/span>\n    <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"video\/webm\"<\/span>\n  \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Your browser doesn't support HTML5 video.<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">video<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>If you check your browser, you should see a non-interactive player.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_FD9C71930CCF880E72011A38A6294DD970A32CD4C820AFFF872B8729AD63F6C3_1651169802537_CleanShot+2022-04-28+at+22.16.202x.png\" alt=\"image of the moon showing example of a video that is not customized or interactive.\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"894\"\/><\/p>\n<h3>Toggle the Pause\/Play State<\/h3>\n<p>To add the pause and play functionality to our player, let\u2019s update our <code>index.html<\/code> file with the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"video-player\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"video\"<\/span>&gt;<\/span>\/\/...<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">video<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"controls\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"controls__button toggleButton\"<\/span> <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Toggle Play\"<\/span>&gt;<\/span>\u25ba<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In order to add some interactivity to your JavaScript video player, add the following to your <code>script.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> video = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\".video\"<\/span>);\n<span class=\"hljs-keyword\">const<\/span> toggleButton = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\".toggleButton\"<\/span>);\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">togglePlay<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">if<\/span> (video.paused || video.ended) {\n    video.play();\n  } <span class=\"hljs-keyword\">else<\/span> {\n    video.pause();\n  }\n}\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">updateToggleButton<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  toggleButton.innerHTML = video.paused ? <span class=\"hljs-string\">\"\u25ba\"<\/span> : <span class=\"hljs-string\">\"\u275a\u275a\"<\/span>;\n}\ntoggleButton.addEventListener(<span class=\"hljs-string\">\"click\"<\/span>, togglePlay);\nvideo.addEventListener(<span class=\"hljs-string\">\"click\"<\/span>, togglePlay);\nvideo.addEventListener(<span class=\"hljs-string\">\"play\"<\/span>, updateToggleButton);\nvideo.addEventListener(<span class=\"hljs-string\">\"pause\"<\/span>, updateToggleButton);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We started by selecting the <code>video<\/code> element, which gives access to the video attributes and methods. We then selected the <code>button<\/code> element and added an event listener to it that triggers the <code>togglePlay<\/code> function when clicked. The <code>togglePlay<\/code> function executes a condition that toggles playing or pausing the video based on its current state.<\/p>\n<p>Next, we added a <code>play<\/code> and <code>pause<\/code> event listener to the <code>video<\/code> element that calls the <code>updateToggleButton<\/code> function, which updates based on the video\u2019s state.<\/p>\n<p>After that, you should be able to pause and play the video by clicking on the button or the video itself.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_FD9C71930CCF880E72011A38A6294DD970A32CD4C820AFFF872B8729AD63F6C3_1651169956072_CleanShot+2022-04-28+at+22.18.51.gif\" alt=\"GIF image of video of the moon showing example of html5 player with pause and play enabled\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"800\" height=\"372\"\/><\/p>\n<h3>Implement Progress Bar<\/h3>\n<p>To add a progress bar that updates the video when played, update your <code>index.html<\/code> file with the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>Video Player<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"video-player\"<\/span>&gt;<\/span>\n  \/\/...\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"controls\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"progress\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"progress__filled\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"controls__button toggleButton\"<\/span> <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Toggle Play\"<\/span>&gt;<\/span>\u25ba<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>To make your JavaScript video player progress bar interactive, Update your <code>script.js<\/code> file to look like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> video = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\".video\"<\/span>);\n<span class=\"hljs-keyword\">const<\/span> toggleButton = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\".toggleButton\"<\/span>);\n<span class=\"hljs-keyword\">const<\/span> progress = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\".progress\"<\/span>);\n<span class=\"hljs-keyword\">const<\/span> progressBar = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\".progress__filled\"<\/span>);\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">togglePlay<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">if<\/span> (video.paused || video.ended) {\n    video.play();\n  } <span class=\"hljs-keyword\">else<\/span> {\n    video.pause();\n  }\n}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">updateToggleButton<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  toggleButton.innerHTML = video.paused ? <span class=\"hljs-string\">\"\u25ba\"<\/span> : <span class=\"hljs-string\">\"\u275a \u275a\"<\/span>;\n}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handleProgress<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> progressPercentage = (video.currentTime \/ video.duration) * <span class=\"hljs-number\">100<\/span>;\n  progressBar.style.flexBasis = <span class=\"hljs-string\">`<span class=\"hljs-subst\">${progressPercentage}<\/span>%`<\/span>;\n}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">scrub<\/span>(<span class=\"hljs-params\">e<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> scrubTime = (e.offsetX \/ progress.offsetWidth) * video.duration;\n  video.currentTime = scrubTime;\n}\n\ntoggleButton.addEventListener(<span class=\"hljs-string\">\"click\"<\/span>, togglePlay);\nvideo.addEventListener(<span class=\"hljs-string\">\"click\"<\/span>, togglePlay);\nvideo.addEventListener(<span class=\"hljs-string\">\"play\"<\/span>, updateToggleButton);\nvideo.addEventListener(<span class=\"hljs-string\">\"pause\"<\/span>, updateToggleButton);\n\nvideo.addEventListener(<span class=\"hljs-string\">\"timeupdate\"<\/span>, handleProgress);\nprogress.addEventListener(<span class=\"hljs-string\">\"click\"<\/span>, scrub);\n<span class=\"hljs-keyword\">let<\/span> mousedown = <span class=\"hljs-literal\">false<\/span>;\nprogress.addEventListener(<span class=\"hljs-string\">\"mousedown\"<\/span>, () =&gt; (mousedown = <span class=\"hljs-literal\">true<\/span>));\nprogress.addEventListener(<span class=\"hljs-string\">\"mousemove\"<\/span>, (e) =&gt; mousedown &amp;&amp; scrub(e));\nprogress.addEventListener(<span class=\"hljs-string\">\"mouseup\"<\/span>, () =&gt; (mousedown = <span class=\"hljs-literal\">false<\/span>));\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We selected the progress bar DOM element and added an event listener to the <code>video<\/code> object that executes the <code>handleProgress<\/code> function on <code>timeupdate<\/code>. The <code>handleProgress<\/code> function calculates the percentage of the video\u2019s current time relative to its total duration and then updates the style as the video progresses.<\/p>\n<p>We also added a <code>scrub<\/code> function to scrub the video to a specific point in relation to the progress bar.<\/p>\n<p>Save the changes and preview the app in your browser to see the updated state of the video player.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_FD9C71930CCF880E72011A38A6294DD970A32CD4C820AFFF872B8729AD63F6C3_1651170257008_CleanShot+2022-04-28+at+22.23.56.gif\" alt=\"GIF image of video of the moon showing example html video player with customized progress bar.\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"800\" height=\"356\"\/><\/p>\n<h3>Add Volume and Playback Rate Slider<\/h3>\n<p>To add custom sliders that will be used to manage the volume and playback rate states, update your <code>index.html<\/code> file with the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"video-player\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"video\"<\/span>&gt;<\/span>\/\/...<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">video<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"controls\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"progress\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"progress__filled\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"controls__button toggleButton\"<\/span> <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Toggle Play\"<\/span>&gt;<\/span>\u25ba<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n\n  \/\/ Add these\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n    <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"range\"<\/span>\n    <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"volume\"<\/span>\n    <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"controls__slider\"<\/span>\n    <span class=\"hljs-attr\">min<\/span>=<span class=\"hljs-string\">\"0\"<\/span>\n    <span class=\"hljs-attr\">max<\/span>=<span class=\"hljs-string\">\"1\"<\/span>\n    <span class=\"hljs-attr\">step<\/span>=<span class=\"hljs-string\">\"0.05\"<\/span>\n    <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"1\"<\/span>\n  \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n    <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"range\"<\/span>\n    <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"playbackRate\"<\/span>\n    <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"controls__slider\"<\/span>\n    <span class=\"hljs-attr\">min<\/span>=<span class=\"hljs-string\">\"0.5\"<\/span>\n    <span class=\"hljs-attr\">max<\/span>=<span class=\"hljs-string\">\"2\"<\/span>\n    <span class=\"hljs-attr\">step<\/span>=<span class=\"hljs-string\">\"0.1\"<\/span>\n    <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"1\"<\/span>\n  \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We added two <code>input<\/code> tags with a <code>type<\/code> of <code>range<\/code> with a predefined <code>min<\/code> and <code>max<\/code> value for the volume and playback rate, respectively.<\/p>\n<p>Now update your <code>script.js<\/code> file with the following code to make the sliders functional:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> video = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\".video\"<\/span>);\n<span class=\"hljs-keyword\">const<\/span> toggleButton = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\".toggleButton\"<\/span>);\n<span class=\"hljs-keyword\">const<\/span> progress = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\".progress\"<\/span>);\n<span class=\"hljs-keyword\">const<\/span> progressBar = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\".progress__filled\"<\/span>);\n<span class=\"hljs-comment\">\/\/ Add this<\/span>\n<span class=\"hljs-keyword\">const<\/span> sliders = <span class=\"hljs-built_in\">document<\/span>.querySelectorAll(<span class=\"hljs-string\">\".contols__slider\"<\/span>);\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">togglePlay<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-comment\">\/\/...<\/span>\n}\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">updateToggleButton<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-comment\">\/\/...<\/span>\n}\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handleProgress<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-comment\">\/\/...<\/span>\n}\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">scrub<\/span>(<span class=\"hljs-params\">e<\/span>) <\/span>{\n  <span class=\"hljs-comment\">\/\/...<\/span>\n}\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handleSliderUpdate<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  video&#91;<span class=\"hljs-keyword\">this<\/span>.name] = <span class=\"hljs-keyword\">this<\/span>.value;\n}\n<span class=\"hljs-comment\">\/\/...<\/span>\nsliders.forEach(<span class=\"hljs-function\">(<span class=\"hljs-params\">slider<\/span>) =&gt;<\/span> {\n  slider.addEventListener(<span class=\"hljs-string\">\"change\"<\/span>, handleSliderUpdate);\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We selected the <code>slider<\/code> elements and attached an event listener to each of them that triggers the <code>handleSliderUpdate<\/code> function. This function uses the slider\u2019s <code>name<\/code> and <code>value<\/code> attributes to define the slider\u2019s state.<\/p>\n<p>If you preview the page in your browser, you should see the sliders.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_FD9C71930CCF880E72011A38A6294DD970A32CD4C820AFFF872B8729AD63F6C3_1651170857580_CleanShot+2022-04-28+at+22.34.052x.png\" alt=\"GIF image of video of Charles Lindberg showing example html video player with a customized slider\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"877\"\/><\/p>\n<h3>Add Skip Controls<\/h3>\n<p>Add the following to your <code>index.html<\/code> file:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">&lt;div <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span><\/span>=<span class=\"hljs-string\">\"video-player\"<\/span>&gt;<span class=\"hljs-comment\">\/\/...&lt;\/div&gt;<\/span>\n<span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"controls\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"progress\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"progress__filled\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"controls__button toggleButton\"<\/span> <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Toggle Play\"<\/span>&gt;<\/span>\u25ba<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> \/\/<span class=\"hljs-attr\">...<\/span> \/&gt;<\/span> <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> \/\/<span class=\"hljs-attr\">...<\/span> \/&gt;<\/span>\n\n  <span class=\"hljs-comment\">&lt;!-- Add these --&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"controls__button\"<\/span> <span class=\"hljs-attr\">data-skip<\/span>=<span class=\"hljs-string\">\"-10\"<\/span>&gt;<\/span>\u00ab 10s<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"controls__button\"<\/span> <span class=\"hljs-attr\">data-skip<\/span>=<span class=\"hljs-string\">\"25\"<\/span>&gt;<\/span>10s \u00bb<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We added two buttons with data attributes that will be accessed with JavaScript. To make the buttons functional, update your <code>script.js<\/code> file with the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/...<\/span>\n\n<span class=\"hljs-comment\">\/\/ Add this<\/span>\n<span class=\"hljs-keyword\">const<\/span> skipBtns = <span class=\"hljs-built_in\">document<\/span>.querySelectorAll(<span class=\"hljs-string\">\"&#91;data-skip]\"<\/span>);\n<span class=\"hljs-comment\">\/\/...<\/span>\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handleSliderUpdate<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  video&#91;<span class=\"hljs-keyword\">this<\/span>.name] = <span class=\"hljs-keyword\">this<\/span>.value;\n}\n\n<span class=\"hljs-comment\">\/\/ Add this<\/span>\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handleSkip<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  video.currentTime += +<span class=\"hljs-keyword\">this<\/span>.dataset.skip;\n}\n<span class=\"hljs-comment\">\/\/...<\/span>\n\n<span class=\"hljs-comment\">\/\/ Add this<\/span>\nskipBtns.forEach(<span class=\"hljs-function\">(<span class=\"hljs-params\">btn<\/span>) =&gt;<\/span> {\n  btn.addEventListener(<span class=\"hljs-string\">\"click\"<\/span>, handleSkip);\n});\n\n<span class=\"hljs-keyword\">let<\/span> mousedown = <span class=\"hljs-literal\">false<\/span>;\nprogress.addEventListener(<span class=\"hljs-string\">\"click\"<\/span>, scrub);\nprogress.addEventListener(<span class=\"hljs-string\">\"mousedown\"<\/span>, () =&gt; (mousedown = <span class=\"hljs-literal\">true<\/span>));\nprogress.addEventListener(<span class=\"hljs-string\">\"mousemove\"<\/span>, (e) =&gt; mousedown &amp;&amp; scrub(e));\nprogress.addEventListener(<span class=\"hljs-string\">\"mouseup\"<\/span>, () =&gt; (mousedown = <span class=\"hljs-literal\">false<\/span>));\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We selected our buttons using the <code>querySelectorAll<\/code> method and added a listener to each button that calls the <code>handleSkip<\/code> function on click. This function then updates the video\u2019s current time based on the value specified in the <code>data<\/code> attribute.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_FD9C71930CCF880E72011A38A6294DD970A32CD4C820AFFF872B8729AD63F6C3_1651171038337_CleanShot+2022-04-28+at+22.36.50.gif\" alt=\"GIF image of video of the USA going to the moon showing example HTML5 video player code skip controls in place\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"800\" height=\"378\"\/><\/p>\n<h3>Add Keyboard Shortcuts<\/h3>\n<p>We can take advantage of the default keyboard <code>keydown<\/code> event to customize the video player further. To add a keyboard shortcut to the application, add this to the bottom of your <code>script.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-built_in\">document<\/span>.addEventListener(<span class=\"hljs-string\">\"keydown\"<\/span>, (e) =&gt; {\n  <span class=\"hljs-keyword\">if<\/span> (e.code === <span class=\"hljs-string\">\"Space\"<\/span>) togglePlay();\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>To keep things simple, we added just a keyboard shortcut that toggles play when the space key on the keyboard is pressed. You can log the event object to the console to see other properties.<\/p>\n<p>Find the project <a href=\"https:\/\/github.com\/ifeoma-imoh\/Custom-Html5-Video-Player\">here<\/a> on GitHub.<\/p>\n<h2>Conclusion<\/h2>\n<p>So far, we\u2019ve looked at the default HTML5 video element and how to create custom video player controls for it, but you don\u2019t have to stop here. Discover how <a href=\"https:\/\/cloudinary.com\/products\/video\">Cloudinary gives you a powerful suite of video tools<\/a> to help you build beautiful, expertly customized videos and more.<\/p>\n<p><strong>Resources you may find helpful:<\/strong><\/p>\n<ul>\n<li>\n<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Element\/video\">MDN Documentation for the Html5 <code>video<\/code> Element<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/cloudinary.com\/documentation\/video_player_api_reference\">Cloudinary Video Player API reference<\/a>\n<\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":29569,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[426,134,145,382,303],"class_list":["post-27761","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-featured","tag-guest-post","tag-html5","tag-player-video","tag-video"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>How to Create a Custom Video Player in HTML5 With JavaScript<\/title>\n<meta name=\"description\" content=\"Learn how to customize video controls in HTML5 on an HTML document and define a custom video player that has controls independent of the browser defaults.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build a Custom HTML5 Video Player With JavaScript\" \/>\n<meta property=\"og:description\" content=\"Learn how to customize video controls in HTML5 on an HTML document and define a custom video player that has controls independent of the browser defaults.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2023-06-16T14:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-10-10T22:05:44+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1683668304\/Blog-custom-video-player\/Blog-custom-video-player.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Build a Custom HTML5 Video Player With JavaScript\",\"datePublished\":\"2023-06-16T14:00:00+00:00\",\"dateModified\":\"2025-10-10T22:05:44+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript\"},\"wordCount\":8,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1683668304\/Blog-custom-video-player\/Blog-custom-video-player.jpg?_i=AA\",\"keywords\":[\"Featured\",\"Guest Post\",\"HTML5\",\"Player Video\",\"Video\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2023\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript\",\"url\":\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript\",\"name\":\"How to Create a Custom Video Player in HTML5 With JavaScript\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1683668304\/Blog-custom-video-player\/Blog-custom-video-player.jpg?_i=AA\",\"datePublished\":\"2023-06-16T14:00:00+00:00\",\"dateModified\":\"2025-10-10T22:05:44+00:00\",\"description\":\"Learn how to customize video controls in HTML5 on an HTML document and define a custom video player that has controls independent of the browser defaults.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1683668304\/Blog-custom-video-player\/Blog-custom-video-player.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1683668304\/Blog-custom-video-player\/Blog-custom-video-player.jpg?_i=AA\",\"width\":2000,\"height\":1100,\"caption\":\"Image showing example of video of the moon and the custom video player html that was used to create it.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Build a Custom HTML5 Video Player With JavaScript\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to Create a Custom Video Player in HTML5 With JavaScript","description":"Learn how to customize video controls in HTML5 on an HTML document and define a custom video player that has controls independent of the browser defaults.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript","og_locale":"en_US","og_type":"article","og_title":"Build a Custom HTML5 Video Player With JavaScript","og_description":"Learn how to customize video controls in HTML5 on an HTML document and define a custom video player that has controls independent of the browser defaults.","og_url":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript","og_site_name":"Cloudinary Blog","article_published_time":"2023-06-16T14:00:00+00:00","article_modified_time":"2025-10-10T22:05:44+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1683668304\/Blog-custom-video-player\/Blog-custom-video-player.jpg?_i=AA","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript"},"author":{"name":"","@id":""},"headline":"Build a Custom HTML5 Video Player With JavaScript","datePublished":"2023-06-16T14:00:00+00:00","dateModified":"2025-10-10T22:05:44+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript"},"wordCount":8,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1683668304\/Blog-custom-video-player\/Blog-custom-video-player.jpg?_i=AA","keywords":["Featured","Guest Post","HTML5","Player Video","Video"],"inLanguage":"en-US","copyrightYear":"2023","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript","url":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript","name":"How to Create a Custom Video Player in HTML5 With JavaScript","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1683668304\/Blog-custom-video-player\/Blog-custom-video-player.jpg?_i=AA","datePublished":"2023-06-16T14:00:00+00:00","dateModified":"2025-10-10T22:05:44+00:00","description":"Learn how to customize video controls in HTML5 on an HTML document and define a custom video player that has controls independent of the browser defaults.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1683668304\/Blog-custom-video-player\/Blog-custom-video-player.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1683668304\/Blog-custom-video-player\/Blog-custom-video-player.jpg?_i=AA","width":2000,"height":1100,"caption":"Image showing example of video of the moon and the custom video player html that was used to create it."},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/build-a-custom-html5-video-player-with-javascript#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Build a Custom HTML5 Video Player With JavaScript"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1683668304\/Blog-custom-video-player\/Blog-custom-video-player.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27761","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=27761"}],"version-history":[{"count":5,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27761\/revisions"}],"predecessor-version":[{"id":38741,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27761\/revisions\/38741"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/29569"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=27761"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=27761"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=27761"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}