Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
  1. Code
  2. Vue

Build a Music Player With Vuetify

Read Time:19 minsLanguages:
Final product imageFinal product imageFinal product image
What You'll Be Creating

Building apps with Vue.js is easy, fun, and enjoyable. You can build a working app with minimum effort. To prove that, today I'll show you how easy it is to build your own full-featured music player. To make things even easier, we'll use Vuetify.js, a Vue.js powered UI library, which will speed up the UI construction. I can almost feel your impatience, so let's get started. 

You can find the full source code in the GitHub repo. And here is the working demo. To follow this tutorial, you should be familiar with Vue componentsVue single file components, and ES2015 syntax.

Planning the App

Every creation starts with an idea and at least some basic planning. So first we need to decide what we want to build and what functionality we want to implement. It's said that a picture is worth a thousand words, so let's start with a simple sketch of the music player.

Vue music player wireframe sketchVue music player wireframe sketchVue music player wireframe sketch

I made this wireframe so you can get a general notion of the UI we want to build. The next step is to describe the functionality we intend to implement.

As John Johnson says: 

First, solve the problem. Then, write the code.

We'll use that as a source of wisdom, and we'll plan the app out before we start coding it.

App Components

Vue.js is a component-based framework. So we need first to split the app into individual components (five in our case, as shown in the sketch above), and to outline the features and functionality for each of them. 

Title Bar

This component will contain the following parts:

  • a menu on the left side
  • the name of the app in the center
  • three static icons on the right side

Info Panel

This component will show basic information about the currently played track:

  • the track's artist and title on the left side
  • the current track's position and duration on the right side

Control Bars

This component will contain two bars, which will include all the controls necessary to manipulate the audio tracks in the player's playlist.

  • a volume slider with an icon on the left (its appearance will change according to the volume level and when the sound is muted), and volume percentage on the right
  • buttons for playing, pausing, stopping, and skipping the tracks.
  • two buttons on the far right: one for repeating the current track, and one for shuffling the tracks' order of playing
  • a seek bar showing the currently played track's position, with the ability to change it with a mouse click on the bar

Playlist Panel

This component will contain the tracks' playlist with the following functionality:

  • display a track with the proper number, artist, title, and duration properties
  • select a track on single click
  • play a track on double click

Search Bar

This component will offer search functionality in the cases when we want to find and play particular track(s).

Of course, the above outline cannot cover all the details and nuances, and this is perfectly fine. For now, it's enough for us to get an overall picture of the final product. We'll handle all the details and eventual challenges during the building process.

So let's get into the fun part and write some code!

Getting Started

Vuetify's quick start page offers plenty of options to get you started. We'll use one of the pre-made Vue CLI templates called Webpack Simple. Run the following commands in the directory you want to use for this project:

First, install Vue CLI:

Then, create the app: 

Next, go to the app's directory and install all dependencies: 

We'll use Howler.js (a JavaScript audio library) to handle the audio parts of the music player. So we need to include it in the project too. Run the following command:

And finally, run the app:

The app will open on localhost:8080 in your default browser. You should see a simple Vuetify app skeleton. 

Tweaking the Template

To adjust it to our needs, we need to clean up the template and tweak it a bit. Rename the App.vue file to Player.vue, open it, delete everything inside, and add the following instead:

We wrap our music player app in the v-app component, which is required for the app to work properly. We also pass the dark prop, to apply the Vuetify dark theme.

Now, open the main.js file, delete the original content, and add the following:

Also, open the index.html file and change the content of the <title> tag to Vue Music Player.

Now, in your browser, you should see an empty dark page. And voila. You are ready to start creating.

Before you start coding, it's good to know that Vuetify offers code snippets and autocompletion for the major code editors: VS Code, Atom, and Sublime. To get the snippets, search for the extension in your favorite editor (vuetify-vscode, or vuetify-atom, or vuetify-sublime).

Build the Title Bar Component

In the src directory, create a new components folder. Then, in that folder, create the PlayerTitleBar.vue file with the following content: 

Here, we use the following Vuetify components: toolbar, menu, button, icon, list, dialog, and card

We separate the menu, the name, and the icons with the <v-spacer> component. To show or hide the dialog, we create the dialog: false data property. Its value will toggle when we click on the About menu item.

Now, in the Player.vue file, import the title bar component, register it in the components object, and add it in the template.

Now, check the result in your browser. You should see the following:

The player title barThe player title barThe player title bar

We'll repeat these three steps for the other four components. So when in the next sections I tell you to import, register and add a component in the template, you should follow the same procedure described here.

Build the Playlist Component

In the root directory, create a new playlist folder and add the audio files you want to play. The file names must be written with underscores between the words and a .mp3 extension at the end—for example, Remember_the_Way.mp3. Now, create an audio tracks array inside Player.vue's data object: 

Each track has title and artist properties, a howl object set to null, and a display property set to true

The display property will be used when we implement the search functionality. Now it is set to true for all tracks, so all of them are visible.

Howler wraps an audio file in a howl object. We set howl to null because we'll populate it dynamically at the creation of the Vue instance. To do that, we use the Vue's created lifecycle hook

This will set a new Howl object for each track in the playlist.

Now, create the PlayerPlaylistPanel.vue component and add this inside: 

First, we pass the prop playlist from the Player.vue file. Next, in the template, we go through each track with the v-for directive and display the track's index, followed by the track's artist and title, and the duration of the track on the far right. We also use v-show bound to the display property. A track will be visible only if display is true.

Now, in the Player.vue file, we import, register, and add the playlist component in the template. Then, we bind the playlist prop to the playlist data property like this: <player-playlist-panel :playlist="playlist"></player-playlist-panel>.

Let's check the result in the browser:

The player playlist panelThe player playlist panelThe player playlist panel

There are two problems here. First, the numbers of the tracks are not correct, and second, the track's duration is shown in milliseconds, but we want it to be in minutes. We'll fix each of these issues by creating a formatting filter. 

In the main.js file, create a numbers filter and a minutes filter, which will be globally accessible. Next, in PlayerPlaylistPanel.vue, we use them like this: {{ index | numbers }} and {{ track.howl.duration() | minutes }}.

Now, if you check the app, everything should display correctly. 

The player playlist panel with fixed numbers and minutesThe player playlist panel with fixed numbers and minutesThe player playlist panel with fixed numbers and minutes

Make Tracks Selectable

In the Player.vue file, add the selectedTrack: null data property and bind it to the playlist component (:selectedTrack="selectedTrack"). Then, we pass the prop in the PlayerPlaylistPanel.vue file (selectedTrack: Object).  

We also add a click event listener to <v-list-tile-content @click="selectTrack(track)"> and then create the selectTrack() method:

Now, back in Player.vue, add the selecttrack event to the playlist component (@selecttrack="selectTrack") and create the selectTrack() method:

Now, if you go to the playlist and click on a track, it will be selected. We can't see it, but we can prove it in the Vue DevTools. In the following screenshot, the second track is selected:

The player playlist with selected track shown in DevTools The player playlist with selected track shown in DevTools The player playlist with selected track shown in DevTools

Row and Selection Styling

The next step is to make the selection visible. To do it, we'll bind a class which will color the selected track in orange and another class which will make even rows darker to make the tracks more distinguishable. Put the following after the v-show directive:

We'll also add another class, which will show a scrollbar when the list gets too big.

We add the necessary classes at the end of the file. 

And that's it. Now, the selected track is highlighted in orange.

The player playlist with selected track coloredThe player playlist with selected track coloredThe player playlist with selected track colored

We'll add the double click play functionality at the end of the next section.

Build the Player Controls Component

Let's create the player controls now. We'll start with the play, pause, and stop buttons. 

Add the Play, Pause, and Stop Buttons

Create the PlayerControlsBars.vue component and add this inside: 

Here, we use the Vuetify toolbar component.

There are three buttons with registered click event listeners. Let's create the methods for them: 

Now, in the Player.vue file, import, register, and add the component in the template. Then, register the event listeners (@playtrack="play"@pausetrack="pause"@stoptrack="stop").

Next, create the index: 0 data property, which will hold the index of the current track. Then, create a computed currentTrack()

And now we can start to create the play, pause, and stop methods. We'll start with the play() method, but before that we need to create the playing: false data property, which will indicate whether the track is playing or not. Add the following code for the play() method:

The method takes an index as the parameter, which specifies the track to be played. First, we get the index of the selected track. Then, we make some checks to determine the value of the index. If an index is provided as an argument and it's a number, then we use it. If a track is selected, we use the index of the selected track. If the selected track is different from the current one, we use the stop() method to stop the current one. Finally, if neither an index argument is passed nor a track is selected, we use the value of the index data property.

Next, we get the howl (based on the index value) for the track and check whether it is playing. If it is, we return nothing; if it's not, we play it. 

Finally, we update the selectedTrack, playing and index data properties.

Let's now create the pause() and stop() methods. 

Here, we just pause or stop the current track and update the playing data property.

Let's also make a track start playing on double click.

Add @dblclick="playTrack()" to <v-list-tile-content> in the PlayerPlaylistPanel.vue and create the playTrack() method:

Register the listener @playtrack="play" in the Player.vue file and voila.

Add the Previous and Next Buttons

Let's now add the previous and next buttons.

Create the skipTrack() method:

Register the event listener (@skiptrack="skip") in Player.vue.

And create the skip() method:

We first check if the direction is next. If so, we increment the index by 1. And if the index gets bigger than the last index in the array, then we start again from zero. When the direction is prev, we decrement the index by 1. And if the index is less than zero, then we use the last index. At the end, we use the index as an argument for the skipTo() method. It stops the current track and plays the next or previous.

Here is how the player looks with the buttons:

The player play buttonsThe player play buttonsThe player play buttons

Add the Volume Slider

Add the following before all the buttons:

Here, we use the Vuetify slider component.

Add the volume: 0.5 data property, and then create the updateVolume() method:

Here, we use the global Howler object to set the volume globally for all howls.

Also, we need to sync the initial Howler volume, which by default is set to 1, to the volume property. If you don't do it, the volume will show 0.5 but will be 1 initially. To do that, we'll use the created hook again:

We want to see the volume level as a percentage on the right of the volume slider, so we add this in the template: {{this.volume * 100 + '%'}} 

Add the Mute Button 

Now, we add a volume icon before the slider. 

The icon will change according to the values of the volume and muted properties.

Add the muted: false data property and create the toggleMute() method:

We use the global Howler object again to set the mute globally, and then we toggle the muted value. 

In the screenshot below, you can see how the volume slider should look:

The player volume sliderThe player volume sliderThe player volume slider

Add the Repeat Button

Add the following after all the buttons:

Add the loop: false property in Player.vue, bind it :loop="loop" and pass the prop (loop: Boolean) in PlayerControlsBars.vue

Now, let's create the toggleLoop() method:

Now, back in Player.vue, register the event listener (@toggleloop="toggleLoop") and create the toggleLoop() method:

At this point, we face a small problem. When a track seeks the end, it just stops. The player doesn't move to the next track, nor does it repeat the current track. To fix that, we need to add the following to the created function after the src property:

Now, when the loop is on, the current track will be repeated. If it's off, the player will move on the next track.

Add the Shuffle Button

Add the following after the repeat button:

Add the shuffle: false property in Player.vue, bind it (:shuffle="shuffle"), and pass the prop (shuffle: Boolean) in PlayerControlsBars.vue

Now, let's create the toggleShuffle() method;

Now, back in Player.vue, register the event listener (@toggleshuffle="toggleShuffle") and create the toggleShuffle() method:

Now, add the following to the skip() method after index = 0:

Here's how your app should look now:

The player repeat and shuffle buttonsThe player repeat and shuffle buttonsThe player repeat and shuffle buttons

Add the Seek Bar

First, in Player.vue, create the seek: 0 property. Then we'll need to watch the playing property in order to update the seek.

This will update the seek value four times per second.

Now, create a computed progress():

Bind it (:progress="progress") in the template. 

Now, in PlayerControlsBars.vue, pass the progress prop (progress: Number) and add another toolbar below the one we've already created:

Here, we use the Vuetify progress component.

Create a computed trackProgress(), which will get the track's progress as a percentage.

And now, create the updateSeek() method: 

Here, we get the progress bar element, which uses the .progress-linear__bar class. I found this with the Browser DevTools. Next, we get the mouse position and the width of the bar. Then, we get the mouse click position as a percentage.

Back in Player.vue, add and register the event listener (@updateseek="setSeek") and create the setSeek() method:

And boom! You can use your mouse to change the position of the played track.

Build the Info Panel Component

Create the PlayerInfoPanel.vue file with the following content:

Here, we pass a prop trackInfo, which we use to populate the track information in our component.

Now, back in Player.vue, import, register and add the component in the template. 

Then, create a computed getTrackInfo()

Next, we bind it in the template (:trackInfo="getTrackInfo") and voila. We get some basic info for the currently played track, as you can see in the screenshot below.

The player info panelThe player info panelThe player info panel

Build the Search Bar Component

Create the PlayerSearchBar.vue file with the following content: 

We create a text field and add the clearable prop to show a clearing icon when we type something.

By using v-model, we bind it to the searchString, which is an empty string initially. And we add an input event listener.

We also pass the playlist prop, which we use in the searchPlaylist() method. In this method, we use the display property and turn it off for each track where the title or artist doesn't match the search string, and we keep it or turn it on for all matches. Finally, if the search string is empty or equal to null, which happens when we clear the field with the clear button, we turn on the display for all tracks.

Now, back in Player.vue, import, register and add the component in the template. 

Bind the playlist property (:playlist="playlist") and check the functionality. Here is how it should look in action:

The player search bar testThe player search bar testThe player search bar test

Some Improvement Ideas

As you can see, with a clear goal and proper planning, building a Vue/Vuetify app can be really easy and enjoyable. You now have a working music player which you can use during your relaxation or coding time. Of course, there is always room for further improvements and additions, so here are some ideas you can try out to make the player even more feature-rich: 

  • multiple playlist support
  • ability to add or remove tracks from the playlist
  • drag-and-drop support
  • ability to sort the tracks
  • audio visualization 


In this tutorial, we saw how easy and enjoyable it can be to build an app with Vue.js, and with Vuetify.js in particular. I hope you enjoyed building this player as much as I did. I'll be glad to see your own improved version of the player. So if you create one, just drop a demo link in the comments!

Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.