Simple HTML Custom Audio Player (Free Download)

Welcome to a quick tutorial and example on how to create an HTML custom audio player. So you want to create a custom audio player? Well, the default <audio> cannot be styled using CSS at the time of writing. The only way is to recreate an audio player – Here’s a simple one that I have made, read on!

 

 

TABLE OF CONTENTS

 

CUSTOM AUDIO PLAYER

All right, let us now get into more details about the custom audio player work. Take note, there is no CSS involved here, only the pure mechanics.

 

HOW TO USE

aud-player.html
<!-- (A) CSS & JS -->
<!-- https://fonts.google.com/icons -->
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="aud-player.css">
<script defer src="aud-player.js"></script>
 
<!-- (B) AUDIO PLAYERS -->
<div class="aWrap" data-src="S1.mp3"></div>
<div class="aWrap" data-src="S2.mp3"></div>

If you just want to use this as a “plugin”:

  1. Load Google Material Icons, the audio player CSS and JS.
  2. Create as many <div class="aWrap" data-src="AUDIO-FILE"> as required.

 

 

PART 1) TIME FORMAT HELPER FUNCTION

aud-player.js
// (A) SUPPORT FUNCTION - FORMAT HH:MM:SS
var timeString = secs => {
  // (A1) HOURS, MINUTES, SECONDS
  let ss = Math.floor(secs),
      hh = Math.floor(ss / 3600),
      mm = Math.floor((ss - (hh * 3600)) / 60);
      ss = ss - (hh * 3600) - (mm * 60);
 
  // (A2) RETURN FORMATTED TIME
  if (hh>0) { mm = mm<10 ? "0"+mm : mm; }
  ss = ss<10 ? "0"+ss : ss;
  return hh>0 ? `${hh}:${mm}:${ss}` : `${mm}:${ss}` ;
};

Right at the top of the Javascript, we have a support function to format the “track time” into a “nice format” of HH:MM:SS.

 

 

PART 2) HTML LAYOUT

aud-player.js
window.addEventListener("load", () => { for (let i of document.querySelectorAll(".aWrap")) {
  // (B) AUDIO + HTML SETUP + FLAGS
  i.audio = new Audio(encodeURI(i.dataset.src));
  i.innerHTML =
    `<button class="aPlay" disabled><span class="aPlayIco material-icons">
      play_arrow
    </span></button>
    <div class="aCron">
      <span class="aNow"></span> / <span class="aTime"></span>
    </div>
    <input class="aSeek" type="range" min="0" value="0" step="1" disabled>
    <span class="aVolIco material-icons">volume_up</span>
    <input class="aVolume" type="range" min="0" max="1" value="1" step="0.1" disabled>`;
  i.aPlay = i.querySelector(".aPlay"),
  i.aPlayIco = i.querySelector(".aPlayIco"),
  i.aNow = i.querySelector(".aNow"),
  i.aTime = i.querySelector(".aTime"),
  i.aSeek = i.querySelector(".aSeek"),
  i.aVolume = i.querySelector(".aVolume"),
  i.aVolIco = i.querySelector(".aVolIco");
  i.seeking = false; // user is dragging the seek bar
  //  ...
}});

On window load, we grab all .aWrap and insert the necessary HTML.

  • <button class="aPlay"> The play/pause button.
  • <span class="aNow"> is the current playtime of the track, <span class="aTime"> is the total time of the track.
  • <input class="aSeek"> Time seek slider, the value is in seconds.
  • <span class="aVolIco> Volume icon and mute button.
  • <input class="aVolume"> Volume slider.

 

 

PART 3) PLAY/PAUSE BUTTON

aud-player.js
// (C) PLAY & PAUSE
// (C1) CLICK TO PLAY/PAUSE
i.aPlay.onclick = () => {
  if (i.audio.paused) { i.audio.play(); }
  else { i.audio.pause(); }
};
 
// (C2) SET PLAY/PAUSE ICON
i.audio.onplay = () => i.aPlayIco.innerHTML = "pause";
i.audio.onpause = () => i.aPlayIco.innerHTML = "play_arrow";
  • (C1) Don’t think this needs any explanation… If the audio is paused, we click to play. If the audio is playing, we click to pause.
  • (C2) Automatically set the play/pause icon on the button.

 

PART 4) TRACK TIME

aud-player.js
// (D) TRACK PROGRESS & SEEK TIME
// (D1) TRACK LOADING
i.audio.onloadstart = () => {
  i.aNow.innerHTML = "Loading";
  i.aTime.innerHTML = "";
};
 
// (D2) ON META LOADED
i.audio.onloadedmetadata = () => {
  // (D2-1) INIT SET TRACK TIME
  i.aNow.innerHTML = timeString(0);
  i.aTime.innerHTML = timeString(i.audio.duration);
 
  // (D2-2) SET SEEK BAR MAX TIME
  i.aSeek.max = Math.floor(i.audio.duration);
 
  // (D2-3) USER CHANGE SEEK BAR TIME
  i.aSeek.oninput = () => i.seeking = true; // prevents clash with (d2-4)
  i.aSeek.onchange = () => {
    i.audio.currentTime = i.aSeek.value;
    if (!i.audio.paused) { i.audio.play(); }
    i.seeking = false;
  };
 
  // (D2-4) UPDATE SEEK BAR ON PLAYING
  i.audio.ontimeupdate = () => {
    if (!i.seeking) { i.aSeek.value = Math.floor(i.audio.currentTime); }
    i.aNow.innerHTML = timeString(i.audio.currentTime);
  };
};
  • (D1) Set a “now loading” message in the track time while the track is loading.
  • (D2) On metadata loaded (information on the track), a whole load of things needs to be done. Not going to explain line-by-line, but basically:
    • (D2-1) Set the HTML track time.
    • (D2-2) Also set the track time on the seek bar.
    • (D2-3) Update the track when the seek bar is being dragged. Take note of how we use the seeking flag here – We do not want the manual seek to clash with the auto-update as the track is playing.
    • (D2-4) Automatically update the HTML seek bar as the track plays.

 

 

PART 5) VOLUME CONTROL

aud-player.js
// (E) VOLUME
i.aVolIco.onclick = () => {
  i.audio.volume = i.audio.volume==0 ? 1 : 0 ;
  i.aVolume.value = i.audio.volume;
  i.aVolIco.innerHTML = (i.aVolume.value==0 ? "volume_mute" : "volume_up");
};
aVolume.onchange = () => {
  i.audio.volume = i.aVolume.value;
  i.aVolIco.innerHTML = (i.aVolume.value==0 ? "volume_mute" : "volume_up");
};

Well… Mute/unmute and update the volume as the user moves the slider.

 

PART 6) ENABLE/DISABLE CONTROLS

aud-player.js
// (F) ENABLE/DISABLE CONTROLS
i.audio.oncanplaythrough = () => {
  i.aPlay.disabled = false;
  i.aVolume.disabled = false;
  i.aSeek.disabled = false;
};
i.audio.onwaiting = () => {
  i.aPlay.disabled = true;
  i.aVolume.disabled = true;
  i.aSeek.disabled = true;
};
  • canplaythrough When the browser has sufficient audio buffer to play through, we enable the controls.
  • waiting When there is an insufficient buffer, we disable the controls.

 

 

DOWNLOAD & NOTES

Here is the download link to the example code, so you don’t have to copy-paste everything.

 

SORRY FOR THE ADS...

But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.

Buy Me A Coffee Code Boxx eBooks

 

EXAMPLE CODE DOWNLOAD

Click here for the source code on GitHub gist, just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

EXTRA BITS & LINKS

That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.

 

ADDING FILE/TRACK NAME

  • Very simple solution – <div>MY TRACK NAME</div><div class="aWrap"></div>.
  • Not simple solution – Add <div class="aWrap" data-name="MY TRACK NAME">, change the HTML in part (B) to adapt the name.

 

CHANGING THE AUDIO SOURCE PROGRAMMATICALLY

  • <div class="aWrap" id="demo">
  • document.getElementById("demo").audio.src = "ANOTHER.MP3";

 

COMPATIBILITY CHECKS

This audio player is obviously not backward compatible with the ancient browsers. But it should work well across all “Grade A” modern browsers.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

4 thoughts on “Simple HTML Custom Audio Player (Free Download)”

  1. Hi,
    Overall you deserve a big compliment, as your other posts are sure a big help
    for anyone who trying to learn to code and you using “Hands-On” examples, what
    makes it fun to look up your posts !

    But this one, is not worth it to be posted… as in 2023 ALL what anyone is
    building MUST be 100% Cellphone friendly and most of those have still pretty
    small screens.

    – Your Player is impossible to be used on a Cellphone…
    UNLESS you move by ONE Player the Volume Control into a “Row” below
    (you provide 2 in your Zip-File)
    TRY it out… on a Cellphone just useless, as you can’t easy control the Track
    or adjust the Volume.

    I write this as my friend ask ME to FIX your code for HIM… Ha ha ha!
    You coded it in 2022… Well, Okay
    but you modified it in March 2023 and didn’t FIX that issue…
    Now that is sad 🙁

    1. * Completely missed the point. Are people going to complain this is “broken” on smartwatches and Raspberry Pi displays next? 😆 CSS is excluded for a reason.

      * You are free to build the interface however you see fit – Add/remove/arrange buttons, change theme, add responsive support.

      * If you want to use it as-it-is, just add .aWrap { flex-wrap:wrap } to allow the elements “break into another row”.

      There’s no need to be critical just because you had to do cosmetic changes in 2023. Such mental diarrhea and passive-aggressive attacks (intentional or unintentional) are uncalled for. Cheers!

Leave a Comment

Your email address will not be published. Required fields are marked *