How to Build a Custom Audio Player in React

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
i've been working on building a custom audio player for a new podcast website that james q quick and i are doing together called compressed actually go check it out it's at compressed.fm and i'll include a link in the description below but on the site you'll see the custom audio player in action and while you're there give our show a listen it's all about web design and development but today i'm going to show you how i built the custom audio player there's a little more complexity than i expected and i had to cobble together a few resources in order to build it within react i'm actually going to break this into a multi-part series so in this video we're going to put the basic blocks together but in the future i'll show you how to get multiple audio players on a page where playing one will stop another one or how to add bookmarks and chapters creating a link that jumps to a specific section of the episode styling the player with a waveform image see there's fun content ahead so be sure to hit the subscribe button below or even better hit the bell icon to receive notifications so you don't miss a thing let's do this if you're new to self teach me channel my name is amy dutton i'm a web designer and developer if you're looking to get into this space sometimes it's hard to know where to start or what resources to trust i want to help you level up and get to where you want to be so if this sounds interesting to you hit the subscribe button below okay last thing before we jump in i wanted to point out that this video is long so if you didn't already notice i've created timestamps listed in the description below feel free to jump around or of course watch this video in multiple sittings okay first things first first things first second thing second let's take a look at the design i know i'm probably stating the obvious here but this will be a list of all the elements that we need to build and everything that we need to account for let's take a look at this in figma so there's a play pause button there's a jump back 30 seconds and a forward 30 seconds button we have a play bar showing where we are in the song and this should also work like any other play bar that you're used to seeing in itunes or spotify you should be able to click on the bar to jump around the podcast or drag the knob to a specific point here we're displaying the current time code on the opposite end we have the duration there's a lot here so let's get started as i mentioned we're going to be building this within react so i'm actually going to start with next.js if you're not familiar with next.js it's a react framework but it gives us a nice starting point it installs react and gives us some scripts out of the box in fact i've gotten to the point where if i want to start a react project i just reach for next.js i know react has create react app but next.js is next level making it so easy to set up custom routes and pages so if we go to the next.js site and click on docs and there's some information here about getting set up quickly so we can just run npx or yarn inside the terminal so i'm gonna just copy this line and for my terminal i actually use hyper it's free and i'll include a link in the description below first within the terminal i need to navigate to my projects folder so the easiest way to do this is actually to type cd and then to find where you need to go within the finder and just drag and drop your folder over and now i can just hit enter and i'm going to paste that line that we copied from the next.js docs and the first thing is it's going to ask me what i want to name my project so i'm going to call this audio aribu audio player and it'll take a hot minute to load that up that is taking a very hot minute perfect now that the scripts have run your screen should look similar to mine next js gives us a few scripts that we can run i'm going to take their recommendation here at the bottom and i can navigate to our new audio player folder by copying this line and now i want to run our project so i'm just going to copy and paste perfect now our server is successfully up and running so we can click on this link inside hyper and it will pull up a browser and you should see something like this let's open up our project within vs code if you've never used next.js before it's totally okay we're not going to go into too much detail here but it's actually pretty simple anything within the pages folder is a route or a url or a page or however you want to think about it so within next.js i can create a new page by just adding a new file to this folder say about.js and now all the content in this file will be available at my site slash about very easy if we kind of walk through the pages folder you'll see that there's already a few files and folders in there for now let's just delete this about file if we look at a little bit more detail at our pages directory you'll see that there's already a few files and folders loaded in we have our underscore app.js file and this is the app's default setting so you can think of this as the main app element i'll typically include different context providers here or authentication or my global styles the api folder is perfect for creating an api or server side functions for your application we won't be doing any of that today so i'm just going to leave that alone the index.js file is our home page so if we look at this file you'll see all the code for the next.js splash page within our browser and this was this page that we were looking at okay so for now let's clear this out and i'm going to delete everything inside our main element and i'm going to type audio player just as some placeholder text now i'm going to delete our footer and i'm going to give that a save so the import head statement at the top allows us to access the html head element and inject our metadata and this is part of the next framework so if you look at the code at the top of the component you can see where we're using the head component to add a title tag and a link to a favicon so i'm going to change our title tag to react audio player and give that a save for styling next.js comes with css modules out of the box and honestly i prefer style components but in this video i really just want to focus on building the audio player so i'm going to use what we already have within the styles folder there are a couple of css files for styling we have the globals.css file which includes well global styles if we look at this a little closer you can see that it's removing the default margin and padding and setting up a default font and some basic link styling the asterisk block means that this style gets applied to every single element on the page the box sizing border box property actually changes how the browser handles the box model it just means that when you define the width for an element that number includes padding instead of tacking it on the end this just makes things a little bit more predictable and easier to calculate if this is confusing to you don't worry about it it's not really going to affect us today but i'll include a link in the description below to some additional information if you want to dive in a little bit deeper if i open up the home.module.css file that it's referencing here at the top of our index.js file you can see that these are styles that format all the content on the home page but real quick i'm going to pull this panel up side by side with the home page code and hide our sidebar i just want to point out exactly how this works so our css file looks pretty normal just regular plain jane css at the top of index.js we're importing our styles then anytime we want to reference a specific class within our react component we're calling curly brackets styles dot the name of our class so this first div is referencing the container class within our css our main element has a class of styles.main on it and that references the main class within our css pretty straightforward right so i'm going to clean out this css file and delete everything except the container and main blocks okay cool so if we look at this real quick within our browser we should have our audio player text centered great so with that piece in place let's get to the meat arby's [Music] in the root of our project i'm going to create a components directory so you can just click on this folder icon and type components and inside i'm going to create a file called audioplayer.js so far so good within this file within our new audio player file i'm going to type raf ce and hit enter this stubs out our boilerplate code magic right well within vs code i have an extension running called es7 react redux graphql react native snippets i know the longest title ever but i'll include a link in the description below but this is great for stubbing out components and boilerplate code just like we did let's move our audio player text from our index.js file into our audio player file so i'm going to copy this and i'm going to paste this into our component and while we're here i also want to change this from a default export to a named export you can do that by wrapping our component name in curly brackets this is just a personal preference but i like for all of my exports to be named exports and this just keeps things nice and clean and consistent because i always know that my components are named exports let's go back to our index.js file and import our new component from now let's display our audio player so where the audio player text is i'm going to swap this out for our component and give that a save okay now if we head over to the browser it should look the exact same as it did before wonderful back in vs code i'm going to close my index.js file and my css file and almost everything that we're going to do now is going to be within our audio player.js so let's step out all the elements that we're going to need within our components div let's get rid of this text and let's add the actual audio so we're going to use a standard html audio tag and actually let's pull up the audio documentation on the w3schools website okay first i want to point out that there are three different audio pages on the site and i know that might be a little confusing so let's walk through all of them plus that will give us a good understanding of how our audio player actually works if you look at the sidebar there is an html media section and below that we have our html audio element and this is for the browser's default audio player so i'm going to click on the try it yourself button and it will appear in a second window with that code okay so you can see that the html is on one side and the browser's audio player is on the other side cool so we have our main audio element and that wraps several different file types letting the browser determine which type it wants to use so let's go over to the sidebar and scroll down to the html reference section and we want to click on this html audio video page so before we were looking at the html item and this is the dom reference this might be a little confusing because a lot of times dom looks just like html but dom stands for document object model so when a web page is loaded the browser actually creates this tree of objects but the dom allows us to get change or delete these html elements so let me explain this in a slightly different way say you're building a website using javascript and go to view source code and the source code looks slightly different than if you just pulled up in your developer tools and inspected the element well your developer tools are rendering the dom and that's what we're talking about it reflects how javascript has changed and deleted those html elements so back to w3schools and what that means for us this dom reference shows us what methods and properties we can access within javascript so if we give this a quick skim the dom reference shows us what methods and properties we can access within javascript if we give this a quick skim you'll see that there's a play and pause if we scroll down a little bit further there's a current time property that allows us to set or return the current playback position there's a duration property that returns the length of the current audio or video file in seconds so already with those four different methods i've listed everything that we need to build the player that we just stubbed out before we jump over to our code though i do want to point out the audio html element in the sidebar and this is basically what we're looking at on the first page but in a little bit more detail so let's see right here on this page it tells us exactly what attributes we have access to on our audio tag so if we scroll down you'll see that there's a table here and we want to pay special attention to the last two attributes the preload and source so we're going to use preload to get all the metadata and instead of using individual source tags we're going to specify the url of the audio player directly on the audio tag okay i know this has been a lot of talking but i just want to make sure you understand exactly what you're doing and why this is not just a copy and paste job okay vs code on the source attribute on our audio tag i'm going to send it a audio file and we're hosting our podcast on simplecast so i'm going to use their url but if you're hosting this somewhere else say amazon s3 you put that url here then as i mentioned we're going to use the preload attribute and i'm going to give it a value of metadata now let's display all the buttons and components that we need so we want a button to be able to jump back 30 seconds then we want a button to be able to toggle between playing and pausing then we want another button that will let us jump forward 30 seconds okay cool cool next up let's display the current time for the clip that we're currently on so right now i'll just say zero zeros then we'll also need to display the duration and let's just give this 249 right now then in between our current time and our duration we want to display our progress bar and fortunately for us html has a built-in range component or a slider and you've probably seen this before on forms where you need to pick a number within a certain range so i'm going to wrap this in a div and say input type range okay if we open this within a browser you'll see all of our components are there looks terrible but everything is there okay so let's handle the styling then our styles folder let's create a new file and we'll call this audioplayer.module.css now let's link it up within our component so in our audio player.js at the top i'll say import styles from stylesaudioplayer.module.css perf okay let's get this in split view to make it a little bit easier to go back and forth okay i'm going to create a class called audio player and this will sit on our main element so i'm going to say class name equals styles dot audio player which has a little a let's use flexbox to get all these items in line so i'm going to say display flex and i'll give it a width of 700 pixels there's a few icons i want to use arrows for forward and back and a play pause icon normally i would probably make these custom svgs but here i want to move quickly so i'm just going to install react icons this is actually a great library that pulls icons from several different libraries bootstrap devicons font awesome ico moon material design missing a bunch but you can select which icon you want and only import that single icon you're not importing the entire library so within the terminal i'm going to stop our server by hitting control c now let's say npm install react icons now let's get our server back up and running so i'm going to say npm run dev i'm going to pull up the react icons documentation and on the left you can see all the libraries that it's pulling from i'm going to search across all of them for an arrow and i like this short stubby one if i click on the icon it will actually copy the name to my clipboard so back in vs code i'm going to import our icon into our audio player so let me say import curly brackets and paste our icon name in i'm going to pull this from react to icons and then we need to tell it which package we're pulling it from so the trick here is that if you look at the icon name it's prefixed with the package name so for this one it's bs for bootstrap so you just type in bs now within our code i'm going to swap out the word back for our icon and this looks just like a normal component okay we also need a right arrow so i'm going to duplicate our import and change left to right and i'm going to do the same thing for forward except i want it to be on the other side okay we also need a play button so i'm going to go back to our react icon documentation and i'm going to search for play and i like this play button from the font awesome library you can see it says fa so same as before i'm going to click on the image to copy it and then in vs code i'm going to add it to our list of imports here at the top except this time i'm going to say from fa and i'm going to do the same thing for our pause icon and i want to use the font awesome pause button so that everything matches so i'm going to duplicate this line and change that to fa pause okay sweet now the play pause button we want to swap out depending on our state so if the player is playing we need the ability to pause or if it's stopped or paused we need to show the play button so we need to pull in reacts use state to keep track at the top of our imports we're already importing react so i'm going to say comma and let's add use state to the list then above our return statement our component let's add use state the way this works is we're just structuring an array so the first value is the name of the state we're just going to make up this name this is going to hold a true or false value and anytime i'm working with booleans which is a true false value i like to say is whatever so is it playing true so i'll just say is playing and the second value so put this in square brackets because this is an array the second value is a function and this is how we update is playing so the naming convention here is to use the same name as our variable is playing but we prepend it with the word set so we say set is playing okay perfect and we can pass a default value to use state so by default when the page loads we don't want our player to play automatically so we'll tell it false okay now within our button we can replace the text with our icons so here we have our play pause and i'm going to use a conditional so i'm going to say if it's playing so if that's true we want it to display our pause button but if it's false then we want to display a play button okay let's give that a save if we flip over to the browser we can see our icons we need to be able to toggle between these two options so we can set up an on click event so on our button code right here we'll say on click and then we can just make up a name for our function so i'm going to call this toggle play pause so now right above our return statement let's define this so i'm going to say const and we'll call our function name and we want to update our is playing by using the set is playing function and we just want it to be the opposite of whatever is playing is so if is playing is true this will set it to false if is playing as false this will set it to true okay let's jump over to our browser and test it out so if we click on our play button it turns to pause if we click on our pause button it turns to play easy peasy lemon squeezy okay now i got a little distracted from our styling so let's go back and wrap that up for the backward and forward 30 i'm going to style these similarly somewhere similarly in my css so this audioplayer.module.css file let's create a class called forward backward and i'm going to stick a class name attribute on our buttons so we'll say class name styles forward backward within our css let's remove the default background and border and the arrows were not quite centered so let's use flexbox to knock these pieces into line so we'll say display flex and align items center that'll make everything centered vertically let's change the font family to mono space and make it a little bit bigger i also want to see the cursor change into a pointer when i hover over the button okay for our hover state let's add some more styles so i'm going to say forward backward and i'm going to use the pseudo element hover to grab that hover state and i want to change the color and i want to make it pink but instead of hard coding in a value let's save it inside a css variable to make our life just a little bit easier so remember our audio player class wraps our entire component so i can define a variable here and it will be accessible to all of the elements inside to create a variable i'm going to use double dashes and i'm going to call this primary since this will be our primary color but it could be anything and then i'm going to paste in my hexadecimal value for pink within my hover state i can use that variable by saying var so it knows i'm pulling in a variable and i'm going to use those double dashes and refer to primary if we check this within the browser we hover over this this is looking good now let's move over to our play button so let's create a class called play pause and we want to add that class to our button give that a save now within our styles i'm going to change the background color to our pink color and i'm going to remove the default border that we get on all of our buttons then i want this to be a circle so i'm going to say border radius is 50 i'm going to give it a width of 75 pixels and a height of 75 pixels i want the icon to be just a little bit bigger so i'm going to say font size is 32 pixels and then i want the icon to have color of yellow so i'm going to create another variable here at the top of my file and call this secondary paste in a yellow hexadecimal color now here at the bottom i can say color and just like with pink i can reference it except this time i'm going to call secondary and let's go back over to our browser and give this a look cool so icon isn't exactly centered so let's reach for flexbox again and i want to center it horizontally so i'm going to say justify content center i'm going to center it vertically so i'm going to say align items center give that a save if we go back and look it's getting a little bit closer but if we click on the button the pause button looks perfectly centered and technically the play button is perfectly centered too but optically it's not it's heavy on the left side so let's shift it just a little bit so i'm going to add a class of play to the play icon itself and within our styles let's make sure that we are positioning it relative i'm going to say left five pixels okay much better okay we're getting there but let's knock all of our elements in line vertically if we go back to our audio player class this wraps everything and we already have a display of flex applied but let's apply align items center give that a save and back to the browser much better okay let's tell the current time and duration next within our component let's add a class name of current time and on our duration let's add one for duration now at the bottom we can add style blocks for these so say current time and duration we can just style both of these at the same time so i'm going to say font family is mono space and we'll make the font size 16 pixels let's look at this now i'm going to give just a little bit of spacing between the forward 30 button and the current time so i'm going to add just a little bit more css so let's say current time margin left is 25 pixels phew okay let's move on to our progress bar and this piece is going to be a little crazy because every browser handles this component differently there's a great article on css tricks that explains how to style this i'll stick a link in the description below for reference all right buckle up and hang on we need to style our input range and normally i would probably do something like this but with css modules you have to use a class name or an id so let's use progress bar it's our class name and we want to add it to our component the easiest way to do this is to create a few css variables a few of these items we're going to style three times once for chrome ones for safari and once for firefox and it will feel a little a lot like repeat but if we keep these properties in css variables we change it once in one place and everything stays in sync in vs code let's create variables for all the properties that we're going to keep track of and remember variables are scope so it's important where you actually list your variables so since these are applying just to our progress bar i'm going to list them inside this class so the first one i'm going to name is a bar background and this is the default progress bar background color i'm going to set this to a light shade of pink so i'm going to paste in that hex value then let's do the seek before width and let's set this to 100 pixels and this is the part of the bar that appears before the scrubby handle or the knobby then let's say seek before color and this is the color of the bar before the handle so we already put the width inside the variable above but this is the actual color so let's make it a darker shade of that light pink so paste in that hex value then we have our knobby and this is the color of our knob or our progress handle or our playhead whatever you want to call it so let's set this to a blue purplish color i'll paste in that hex value and then let's do one for our selected knobby and this is the color of the knob once we've grabbed it and it's selected so this will be turquoise let's put these variables to good use so i'm going to move my code up and we want to hide the default background color of our range slider so i'm going to say appearance is none i'm going to set the background using the variable that we've already created so say background var bar bg and i want it to have rounded corners so i'm going to say border radius is 10 pixels i want to make the position relative and i want to give it a width of 100 and a height of 11 pixels now i want to remove the default outline by setting that to none okay now we need to basically set the exact same properties that we set for chrome except for safari so i'm going to say progress bar and let's leave ourselves a little comment here so we know these are for safari so to target for safari we need to use a special pseudo element so say progress bar double colons webkit slider runnable track we can actually copy all the styles that we wrote for chrome except the appearance property and give that a paste then we want to do the exact same thing for firefox so let's give ourselves a little comment here for fox firefox has its own custom pseudo property so let's call that it is moz range track and we can paste those exact same properties over again now let's add one more piece for firefox to remove the outline we actually need to target one of its special pseudo elements so we'll say progress bar mos focus outer and set this to border 0. next we need to set up the progress bar background color and this is the part that will appear before the knob so if we're dragging this handle around this is the part that we've already played and it will be a different color than the remaining audio so back in vs code let's style this for chrome first so i'm going to say progress bar and these styles will actually work for safari as well so let's add that to our comment and in order to get this to work we are going to use our pseudo element before so that we're injecting this element before our progress bar and when you're using it before in order to get the tag to show up you have to use the content property and we can just use blank quotes to leave that empty next we want to give this a height of 11 pixels then our width we want to be dynamic and we've actually already set up a variable for that called seek before width we want to change the background color and we have a variable for that as well called seek before color then for our corners we want the corners on the left to be rounded to line up with our progress bar but the edge on the right can be straight that's the part that appears underneath the knob so in order to target those corners individually we can say border left top left radius we can make that 10 pixels and border bottom left radius and we'll set that to 10 pixels we want to position this absolutely and we can say top is zero left is zero and we want to make sure that this appears above our progress bar so we can set the z index to 2 and when the user hovers over the bar we want the cursor to change to a pointer so let's give this a save and check this out within chrome awesome it is coming together okay onward and upward to firefox so say progress bar firefox again we have our comment and firefox has its own special pseudo element so we'll call progress bar and this is mo's range progress and let's set our background color to our pseudo element seek before color perfect and then let's set the border radius just like we did for chrome above so we can actually give that a copy and a paste and we can also set the height to 11 pixels now for the knob let's start with chrome and safari so say knobby chrome and safari we'll grab the progress bar and we have a special pseudo element here called webkit slider thumb and we got our comment okay so let's remove the default styling so i'm going to say webkit appearance none then we just want this to be a circle so let's give this a height of 15 pixels and a width of 15 pixels to give it those rounded edges we need to say border radius is 50 let's remove the border and by setting it to none and then we can use our custom variable we already set up for our background color and we want that to be our knobby okay so when the user hovers over the knob we want to change the cursor to a pointer so we can say cursor is pointer then we want to move it up slightly so we'll say position is relative and we want to give it a margin of negative two pixels just to bump it up a little bit on the top and we can say zeros for the other sides we want this to appear on top of the progress bar and the played part so we'll set our z index to three and then let's change our box sizing to border box which is the initial default value okay now when we drag the knob let's change the background color of the knob to and make it just a little bit bigger so in order to do that we'll say progress bar active and we want to grab that webkit slider thumb let's add our comment up here knobby while dragging for chrome and safari okay let's pull this up we want to set transform so it'll get just a little bit bigger and we want to set our background to our selected knobby color now firefox uh we'll get there okay so let's set up our comment this is the knobby for firefox let's grab our progress bar and we're going to use a special firefox pseudo element called nose range thumb let's give ourselves a head start by just copying and pasting the knobby styles from our chrome and safari block and i do want to change a few things here notice i didn't grab the webkit appearance since that's specifically for chrome and safari we can remove this margin because firefox actually places this correctly out of the box and then instead of setting our border to none let's set this to transparent when it's selected in firefox let's go ahead and grab this except we want to add our active pseudo element and just like before we want it to transform it and change the background color i'm going to add my comment okay let's give this a save and check it in all of our browsers so in chrome when we're grabbing this perfect now in firefox okay perfect and then in safari awesome sauce okay great now for the fun part if you weren't having fun already the interaction so let's use javascript to interact with our player and since we already have the beginnings of our play pause let's start there in order to make it easy to grab our audio player let's set up a reference and this is a piece that's built directly into react so at the top of our file where we're importing use state let's also import use ref then right below our state and i'm actually going to add a quick comment here right above our states and keep things nice and documented some people try to avoid comments at all costs and believe the code should be self-documenting and that might be true but man i think you can get there a heck of a lot faster and understand exactly what the code is doing and why i code it a certain way if you leave comments i like to believe that this is coding with empathy it's being kind to other developers that might need to work within your code base and even if you're working alone you're still being kind to your future self so trust me you won't remember what you did six months from now okay so for our reference right below our state i'm going to add our references and the way this works is we want to set up a variable that we can well reference so i'm going to call ours audio player and then we're going to say that this is a reference so we'll say use ref and i'm going to make sure that we remember in the future that this is for our audio component now we actually need to connect it to our audio player so if we scroll down to our html audio element i'm going to add ref equals audio player and we're using curly brackets here because this is javascript now within our toggle play pause function let's add a conditional so we can say if and the name of our state is playing then we want to reference our audio player and it stores a whole bunch of data related to our player in this case we want to grab the current element and play again this play function is available to us as an html dom element so i'll pull up the w3school's documentation again real quick you can see we have this method play and there's another one for pause which is exactly what we'll need for our else statement so let's add that so i'm going to say else audio player dot current stop pause okay now let's open this up within our browser close that hit refresh okay this is really strange if we click once nothing happens we click again and it starts playing but then our toggle state is backwards believe it or not i set us up for failure on purpose so use state is asynchronous so when we update our toggle button by saying set is playing to the opposite it runs out and executes that function it doesn't have time to get back before we run our conditional so the correct way to write this code is to grab the previous value with use state you can grab the previous values i could say set is playing i'm gonna grab the previous value and set it to the opposite the only problem here is that this still doesn't solve our asynchronous issue we need the previous value within that condition so let's actually just pull it out and give it its own variable name say const prev value and we want to set that to whatever is the current is playing then within our state let's set that to the opposite and now let's run our conditional so we'll say prev value because that's our new state okay let's pull this up within our browser give us a refresh and everything seems to be working like a champ okay now let's connect the duration of our track this should actually be pretty easy since there's a duration property just like there was a play pause method so the first thing we need to do is let's create a piece of state to hold our value at the top so i'm going to say const duration and we want to update it using the set duration method say use state and we can set the default here by passing it a value of zero now we can jump down to our jsx and we have a comment here for duration see how helpful these comments are and let's swap out our hard-coded 249 for duration if we give that a save and we open it up within the browser you should see a0 okay perfect cool now let's update it to the correct value based on our audio file and we want this to figure it out once since it won't change so in order to do that we can use react's use effect so at the top of our file let's import use effect then we want to use our use effect hooks at the top of our component right below our state and reference declaration so we'll say use effects so the way this works is it takes a function as the first parameter and an array as the second parameter the function is whatever you want it to do so that's where we'll set the duration and the array tells it when we want it to run use effect if we don't pass in an array it will run every single time the component refreshes if you pass in an empty array it will only run once when the component first loads it may seem like we only want it to run once when the component first loads but the problem is our audio file may or may not have loaded yet so let's tell it to run as soon as the audio player has loaded and it's metadata or when the audio player is ready so in the array we'll say if the audio player exists we can add a question mark to say if audio player exists and if current exists and we want it to update when the loaded metadata is available okay and again loaded metadata is available just like play pause and duration okay we want to do the same thing for our ready state so we'll say audio player question current question ready state now let's write the function that we want it to run we want to update our state so we'll say set duration and we want it to be set to the audio player and it's duration if we look at this within the browser the only problem is that it's within seconds with a decimal okay so let's jump back over to our code and javascript has a built-in function called floor that will allow us to round down so let's abstract this a little bit to make it easier to read i'm going to create a variable called seconds and then we'll call javascript's round function math.floor and we want to pass it our audio's duration so i'm going to cut that and paste that into our function and now we want to set our set duration to seconds so if i give this a save and if we come back over we got rid of the decimal but the only problem is that it's still not formatted correctly so let's write a separate function to reformat our data so let's call this calculate time and this is going to be a new function okay we're going to pass in our seconds first let's figure out how many whole minutes this translates into so i'm going to create a variable called minutes and we can just divide the number of seconds by 60 but to get rid of the decimal place we again need to wrap this in math.floor perfect okay if our minutes is less than 10 then we want to stick a zero in front so let's create another variable to hold this called const returned minutes and we want to say if our minutes is less than 10 then we want to return our minutes with a zero in front otherwise we can just simply display minutes as is if this is zero minutes format looks funny to you it's the same thing as writing zero plus minutes but it's a little bit more succinct so the backticks let us use javascript and line and the dollar sign and curly brackets let the compiler know that we're passing in a javascript variable okay now we need to determine how many seconds so let's stick that inside of variable two so say const seconds and here we can use seconds since the seconds we passed in above is just sex s-e-c-s okay javascript has a math operator called a modulus and it returns the remainder so we want to divide our seconds by 60 again but we only want the minutes we want to determine whatever is left over so instead of using the divide we'll use the percent sign that's the modulus okay and we want to round this down too so say math.floor and wrap that just like returned minutes let's create a variable called returned seconds and we'll say if our seconds is less than 10 we want to put a zero in front of it otherwise we can just return these seconds as is okay now let's stitch our returned minutes in our return seconds and we just want them to be separated by a colon so we'll say return returned minutes return seconds and we'll wrap this with backticks within our jsx let's jump down to where we are listing our let me fix this misspelling real quick let's jump down to where we're displaying our duration in our jsx and let's wrap this with our new function okay and if we head over to the browser you'll see that it's displaying our time just like we wanted and we can actually get rid of those spaces give that a save perfect okay occasionally you might see n-a-n-n-a-n which means not a number and this is displaying because it's trying to display the duration before it's ready so let's add a conditional within our jsx so first we want to check that the duration exists so we're going to use the double input stands and we also want to see if the duration is not a number so we can use a javascript function to see if it is not a number we'll pass it duration but we're checking for the opposite we only want it to run if it's not true and let's wrap this in parentheses so it'll check for both of those items okay cool now while we're at it let's display the current position so just like duration let's add some state to keep track of our current time so if i come back up here to the top let's add a new variable for current time and our update function is going to be set current time and make sure we're using use state and let's set the default to zero so that it's always at the beginning okay if we go down to our jsx where we're displaying the current time right here we have our comment let's swap it out for our dynamic value so i can say current time and then just like duration we want it to be formatted correctly so we'll reuse our calculate time function and pass it that current time value okay so if we check this within the browser it says zero zero which is perfect okay so next our progress bar okay on the range element let's set the default value to zero and if you remember we're setting our played styles with a width inside our css so let's update our custom variable to match the default values so that everything stays in sync so over here in our styles we want to set this to zero okay let's check this within the browser really quick just to make sure that everything is displaying correctly perfect now we want the progress bar to track along as the song plays right now our range slider is a range of 0 to 100 but really it should be zero to however many seconds are in the song and then increasing the inputs value say 30 will advance the song 30 seconds let's set up another reference to make it easier to latch onto our progress bar so at the top we have our reference to our audio player let's also set one up for our progress bar so i'm going to say const progress bar equals use ref and let's set up a quick comment so we can remember this is a reference to our progress bar and then we need to attach it to our input so down here where we have our progress bar range we can hide these for right now we'll say ref is our progress bar now let's jump back up to our use effect where we determine the duration and we'll set the max amount on our progress bar to match the duration so let's grab our progress bar reference and the current item and we'll set the max property to seconds and that seconds is coming from the variable that we set above remember current is referencing the current item in our reference and max is a built-in property on our input range now when we change the range slider we want to update where we are in the song so let's add an onchange event to our range slider and scroll back down we'll say on change and let's have it run a function called change range now let's actually go right that function so i'll come back up here right above my return statement and we'll say const change range let's make sure we spell this correctly perfect and we can grab the current time from our audio player so again that's one of those built-in functions so i'm going to say audio player dot current since we're referencing the current item on our audio play reference we want to grab the current time remember that's one of those properties that's on our audio element and we want it to be equal to the current value of our progress bar so i'll say progress bar dot current dot value then we also need to update our css variable to match and we can do all this within javascript so let's grab our progress bar just like we've been doing so we'll say dot current and then we can grab the style so say style we want to set the property since this was a css property that we created and the first parameter that it takes is in the name of our variable so we'll say seek before width and the second parameter is the value so we're going to use javascript to calculate a percentage and build out the string so i'm going to use backticks and we want to create a percentage to say that something like 25 percent of the song has been played so to figure that out we'll take the current song progress bar dot current dot value and we'll divide it by the duration and remember duration is stored in our state and then let's multiply it by 100 and since we're using this value in css we need to tack on the percentage sign at the end we want to make sure that when we change the knobby it also updates the current time readout next to the progress bar so we can set the current time to update it so we'll pass that the progress bar dot current dot value okay if we look at this within the browser oh brother change range is not defined so i misspelled that no big deal okay give that a save come back over to the browser drag our knobby around the played style moves around like we wanted and the current time updates as well if we play our song and we click around i don't know code not sure regardless you'll see that the song jumps around too now we just need to set it up so that when it's playing the knobby moves too the first time i built this for the compressed dot fm site i wanted to reach for use effect to update the knob use effect would run every time the react component refreshes but that didn't work because use effect doesn't update every second and it's unpredictable about when it chooses to update so in the process of doing research i discovered a built-in javascript function called request animation frame let me explain how it works typically when you want to run a function say every second in javascript you might reach for something like said interval i know i've used this for timers in the past but you can give set interval a name and tell it to start and stop well request animation frame works almost the exact same way you can name it telling it when to start and stop but in this case you're telling the browser that you have an animation you want to run before the next repaint which is actually what i thought use effect did but doesn't in the code to set this up let's create another reference that's right we can set references to more things than just dom elements so back in our code at the top of our file where we declare our references let's create a variable called animation ref and we want to use use ref and let's add a comment here this will reference the animation that we're working on now we want to set up our reference as soon as we hit play and then we want to cancel the animation when we hit pause so let's go to our toggle play pause function and as soon as we set it to play here let's set up a new line and reference our animations we'll say animation ref dot current and this should equal request animation frame and we need to pass this a function and remember request animation frame is a javascript function that we get out of the box so i'll call this while playing and we haven't written that function yet but we will but you could name this function anything that you like okay and then in our else conditional where we pause let's call our javascript function to stop our animation so we'll say cancel animation frame again that's a javascript function that we get out of the box and we want to pass it that reference so we'll say animation ref.current okay cool now let's write our while playing function so let's come down a few lines here and we'll say const while playing and now every frame we want to update the range slider to match the current time and remember we can grab that with a reference we have our progress bar dot current and we want the value to be equal to the audio and we have a reference for that see these references are helpful we have audio player dot current and we need the current time method and the current time method is built into html next up we need to update our css property and we already did this once in our change range function so let's copy that it's down here and we're going to paste that into our while playing function okay now we need to update the current time in our state to match the range slider so we've actually already written this as well and let's paste that in and i do want to take a hot minute and point out that there's a little bit of redundancy here so if you look at the change range function it looks pretty similar so we could abstract these bottom two lines and put them in its own function but i did want to point out that this top line is different they're backwards in the change range method we're updating the range slider and telling the audio player to jump to wherever the range slider is in our while playing function the audio player is playing and we want the range slider to match up with that let's pull this out because we're actually going to reference it again later so i'm going to create a new function called const change player current time let's stub out our function oops okay and let's grab these two lines and we can replace that with our function actually i can grab this and hit command d and it'll select the next instance of it and i'm going to replace that perfect i'll do this a lot while i'm programming i'll write a function notice duplication and then abstract it every time you feel deja vu like i've already done this once that's a good indicator that you can pull this out into its own function now we need to do one more thing in our while playing function as it is right now this function will only run once and we want it to keep running until we tell it to stop when we hit pause so in order for it to run again we need to tell it to call itself we can actually just use the same line from our play conditional if we come up here and we'll paste that into our function so just to review it gets to the end of the function it says hey when you repaint call while playing again and since we're still assigning it to the animation ref that we set up pausing it will stop it phew for me that was the hardest part now let's test this in the browser so if i hit play and it's working cool okay last step and i saved something easy the next and previous 30 buttons we've already laid all the groundwork so this part should go fast on our backward 30 buttons let's scroll down and here's our back 30 button let's add an on click handler and we want to call back 30. we're going to need to write that function so let's come up here and say const back 30. okay first we want to add 30 seconds to our range slider and it's already in seconds so we can just say progress bar dot current dot value equals number number is a javascript function that will take any string and convert it to a number so we're going to reference our progress bar dot current dot value and we want to subtract 30. then we want it to update everything just as we did when we change the range slider so let's call our change range function if we look at that function real quick just so we know exactly what's happening it's updating the audio player based on the range slider and then it's calling the change player current time which updates the styles and our state okay let's give this a spin in the browser i'm gonna hit save and let's give this a refresh okay so i'm going to come forward hit play and it jumps perfect okay now we want to do the same thing for our forward 30 button come back to our code and on our forward 30 button let's add an on click event and we'll say forward 30. let's come up here and add a similar function and i'm actually just going to copy and paste all of this except instead of minus 30 we want plus 30. so if we open this within the browser and hit our forward 30 button it's going to jump forward 30 seconds perfect awesome sauce okay dun dun if you like this video and want to see more videos on web design and development be sure to hit the subscribe button below hit the bell icon to receive notifications when new videos are posted until then keep coding as many of you may or may not know i work for a company called zeal and they actually underwrite my channel that's right they wholeheartedly support what i'm doing on the youtubes frankly i don't know many companies that do that in fact most companies don't even want you to have side projects and in my case zeal not only encourages it they support it anyway they're hiring so if you're looking for a job or even if you're not but you want to work for a great company plus you get to work with me check out their website for the job listing i'll include a link in the description below
Info
Channel: Self Teach Me
Views: 11,712
Rating: undefined out of 5
Keywords: react, javascript, reactjs, audio player, custom audio player css - javascript tutorial, custom audio player, custom audio player javascript, custom audio player css, custom audio player html css, react audio player, react audio player tutorial, react audio player component, custom audio player tutorial, audio player tutorial
Id: sqpg1qzJCGQ
Channel Id: undefined
Length: 63min 37sec (3817 seconds)
Published: Tue May 11 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.