Simple Javascript/CSS Jukebox Tutorial
I call this a jukebox not only beceause I've come across a few other personal pages that call their music player one, but because its features are more limited than a modern music player. Like a jukebox, it has a selection of songs that the patron can select, and the user cannot change the volume or spot within a song. This makes our web jukebox much more simple because we dont need to alter the volume or time slider
I'm making this tutorial because in my own efforts to make my jukebox, I only found needlessly complex code, so I made my own from scratch! The length of this page may seem long, but the code really is simple! I just like to over explain things ^^
Note: my knowledge of javascript is very limited, I'm just throwing together bits I've learned during my efforts
Update 2/5/24: altered code to increase accessibility and updated tutorial language/organization for clairity
Summary
Heres the code in order of how it would show up in the HTML document
.jukebox {
position: relative;}
.jukebox ul {
display: none;
position: absolute;
top: 100%;
left: 0px;}
.jukebox:hover ul, .activate:focus + ul, .jukebox:focus-within > ul {
display: inline-block;}
This CSS goes in the style element above the body.
<script>
function stopmusic() {
var y = document.getElementsByTagName('audio');
for(var j=0; j<y.length; j++) {
y[j].pause();}
document.getElementById('marq').innerHTML = 'no music is playing';}
function playsong() {
var y = document.getElementsByTagName('audio');
for(var j=0; j<y.length; j++) {
y[j].pause();}
var songvalue = event.target.value;
document.getElementsByTagName('audio')[songvalue].currentTime = 0;
document.getElementsByTagName('audio')[songvalue].play();
document.getElementById('marq').innerHTML = event.target.title;}
</script>
This JS goes in a script element above the body.
<div class="jukebox">
<button class="activate"><img src="https://solaria.neocities.org/smallgifs/cdspin.gif"></button>
<ul>
<button onclick="stopmusic()" >stop music</button>
<li><button value="0" onclick="playsong()">crumblin_down.mp3
<audio ><source src="https://media-upload.net/uploads/5S9FeDnNyrOE.mp3" type="audio/mp3"></audio>
</button></li>
<li><button value="1" onclick="playsong()">dragula.mp3
<audio ><source src="https://media-upload.net/uploads/e6gThUtmqE2z.mp3" type="audio/mp3"></audio>
</button></li>
<li><button value="2" onclick="playsong()">have_you_ever_seen_the_rain.mp3
<audio ><source src="https://media-upload.net/uploads/gTKMVftE8oCu.mp3" type="audio/mp3"></audio>
</button></li>
<li><button value="3" onclick="playsong()">i_hate_myself_for_loving_you.mp3
<audio><source src="https://media-upload.net/uploads/TRNy3ljbSKXa.mp3" type="audio/mp3"></audio>
</button></li>
<li><button value="4" onclick="playsong()">i_would_walk_500_miles.mp3
<audio><source src="https://media-upload.net/uploads/KGSmbhNQCsfF.mp3" type="audio/mp3"></audio>
</button></li>
</ul>
<marquee >
<p id="marq">select a song!</p>
</marquee>
<script>
var y = document.getElementsByTagName('audio');
for(var j=0; j<y.length; j++) {
y[j].onended = function() {
document.getElementById('marq').innerHTML = 'select a song!';};}
</script>
</div>
This is the HTML in the body, notice the script element in the HTML body.
The following sections explain the code in detail if you are confused or need help ^^
HTML
Lets start with the HTML (then Javascript, lastly CSS). I will also skip the marquee for now.
<div class="jukebox">
<button class="activate"><img src="https://solaria.neocities.org/smallgifs/cdspin.gif"></button>
<ul>
<button onclick="stopmusic()" >stop music</button>
<li><button value="0" onclick="playsong()">crumblin_down.mp3
<audio ><source src="https://media-upload.net/uploads/5S9FeDnNyrOE.mp3" type="audio/mp3"></audio>
</button></li>
<li><button value="1" onclick="playsong()">dragula.mp3
<audio ><source src="https://media-upload.net/uploads/e6gThUtmqE2z.mp3" type="audio/mp3"></audio>
</button></li>
<li><button value="2" onclick="playsong()">have_you_ever_seen_the_rain.mp3
<audio ><source src="https://media-upload.net/uploads/gTKMVftE8oCu.mp3" type="audio/mp3"></audio>
</button></li>
<li><button value="3" onclick="playsong()">i_hate_myself_for_loving_you.mp3
<audio><source src="https://media-upload.net/uploads/TRNy3ljbSKXa.mp3" type="audio/mp3"></audio>
</button></li>
<li><button value="4" onclick="playsong()">i_would_walk_500_miles.mp3
<audio><source src="https://media-upload.net/uploads/KGSmbhNQCsfF.mp3" type="audio/mp3"></audio>
</button></li>
</ul>
</div>
- First we make a div container for the jukebox, this holds the songs, the image (and eventually the marquee)
- Next is the image I used to represent the jukebox inside of a button.
- The button does not use any JS, but it does increase accessibility by allowing keyboard users to tab to the element and see the list of songs, which would not be possible with a hover effect alone
- a button is not necessary if your song selection is shown all the time rather than just on hover
- Before the songs is a stop music button so its quick to access
- Each song is activated with a button holding the same function for each
- again the button allows keyboard users to select a song
- I put the song buttons in a list so the amount of items would be read to a screen reader user, but they don't need to be in a list
Lets look closer at each list item:
<li><button value="0" onclick="playsong()">crumblin_down.mp3
<audio><source src="https://media-upload.net/uploads/5S9FeDnNyrOE.mp3" type="audio/mp3"></audio>
</button></li>
value="0"
- I gave each song button a value, with the first one starting at zero, this is used to identify the song in the javascript- it is important that these are numbered like this for the right song to play
- I chose the value attribute for them, but I imagine you could use a different attribute as long you put the same numbers inside of them
onclick="playsong()"
- the javascript function that happens when the user clicks the song- the actual javascript code that happens will be contained else where
- each song button will have the same function
- crumblin_down.mp3 - this is the text we want to show up for the user to click on: the song name (this isnt actually a file, i just named it like one for fun)
<audio><source src="https://media-upload.net/uploads/5S9FeDnNyrOE.mp3" type="audio/mp3"></audio>
- the code for embeding a music file into a webpage
- note how the src attribute is in a source tag between the audio tags, rather than just in the audio tag
src=""
- the file url goes inside the source attribute- if these are your own songs you can upload the files directly to neocities
- if it is copywrited material like mine, you can upload them to a third party site you can hotlink to, so you dont violate neocities terms of service (i used media-upload.net, catbox.moe is another option)
- we would use
<audio controls>
if we wanted to allow the user to adjust the volume and position of each song, but each browser styles the controls differently, and you need a lot of extra javascript to style them your own way. since i just want a basic jukebox i omit the controls
JavaScript
The following code is in the head of the document (but not in the style section), you could also put it in the body of the document
<script>
function stopmusic() {
var y = document.getElementsByTagName('audio');
for(var j=0; j<y.length; j++) {
y[j].pause();}
function playsong() {
var y = document.getElementsByTagName('audio');
for(var j=0; j<y.length; j++) {
y[j].pause();}
var songvalue = event.target.value;
document.getElementsByTagName('audio')[songvalue].currentTime = 0;
document.getElementsByTagName('audio')[songvalue].play();}
</script>
- I have two functions:
playsong() {}
andstopmusic() {}
- function is declared before them to let javascript know that they are functions
Stop Music Function
function stopmusic() {
var y = document.getElementsByTagName('audio');
for(var j=0; j<y.length; j++) {
y[j].pause();}
- this function pauses all audio elements
- the first line makes a variable y and defines it as the audio element
- if you have audio elements on your page that are not a part of your playlist, try
var y = document.querySelectorAll('.jukebox audio');
if you don't want those to also stop
- if you have audio elements on your page that are not a part of your playlist, try
- the next line basically makes it so that every audio element is selected, rather than just the first one (see my javascript tutorial for more details)
- the third line pauses the selected audio elements -
pause()
is a predefined javascript function that javascript already knows how to use
Play Song Function
function playsong() {
var y = document.getElementsByTagName('audio');
for(var j=0; j<y.length; j++) {
y[j].pause();}
var songvalue = event.target.value;
document.getElementsByTagName('audio')[songvalue].currentTime = 0;
document.getElementsByTagName('audio')[songvalue].play();
- the first section is the same as the stop song function. Here its used to stop any other songs the user clicked on, so there is no audio overlap
var songvalue = event.target.value;
document.getElementsByTagName('audio')[songvalue].currentTime = 0;
document.getElementsByTagName('audio')[songvalue].play();
- the second section plays the song!
- the first line creates another variable: songvalue
- this is where the value i gave each list element in the HTML comes in
- event.target identifies the clicked button
- .value identifies the value we gave the clicked button
document.getElementsByTagName('audio')[songvalue]
identifies the audio elements - the brackets[]
identifies which audio element, since we have multiple- in these brackets goes a number
- document.getElementsByTagName('audio')[0] - the first audio element
- document.getElementsByTagName('audio')[1] - the second audio element
- document.getElementsByTagName('audio')[2] - the third audio element
- since we need a [0] to get the first audio element, we had to give the first song button a value of 0
- the variable songvalue picks the value for the song button clicked, thus when placed in the brackets
document.getElementsByTagName('audio')[songvalue]
it chooses the corresponding audio element
- in these brackets goes a number
.currentTime = 0;
- makes the song selected start at the beginning- useful if a user listened to a song partly through, clicked on a another song, and then clicked back onto the first one, preventing the first song from resuming where it was left off
.play()
- a predefined javascript function that plays an audio or video element
CSS
The css is pretty simple, infact if you want the song menu to be visable all the time, rather than on hover, you can style everything however you like. This CSS will show you how to make the list menu appear when the user hovers over the jukebox div
.jukebox {
position: relative;}
.jukebox ul {
display: none;
position: absolute;
top: 100%;
left: 0px;}
.jukebox:hover ul, .activate:focus + ul, .jukebox:focus-within > ul {
display: inline-block;}
This is a basic formatting of the css, with most of the personal preference styling removed for clairity. Things like width and backgrounds are up to you to decide
- first is the class .jukebox used to style the main conataining div element
position: relative;
is the most important part - this allows us to position the song list in relationship to the jukebox div- you probably want to give it a width
.jukebox ul
- this styles the whole list within the jukebox div- if you didn't use a list you will want a div to contain your buttons; replace "ul" with that div's class or ID
position: absolute;
- the needed counterpart toposition: relative
in order for the list to be positioned relative to the jukebox div- top and left determine how far away the list is from the jukebox div
display: none
- this makes it so that the song list is hidden
.jukebox:hover ul { display: inline-block;}
- when the user hovers over the jukebox div, the whole list will show up- i use inline-block beacuse I dont need the list element to be any wider than the longest song title
.activate:focus + ul
this is where the button we made to conatin the jukebox element comes in! this makes the list appear when a keyboard user tabs to the image button- a plus sign is used because the list is next to the image button rather than inside of it
.jukebox:focus-within > ul
this keeps the song list showing while the keyboard user is tabbing into the song buttons within the list
Marquee
Completeley optional, but this adds scrolling text that lets the viewer know which song is playing, or if any music is playing at all
<marquee >
<p id="marq">select a song!</p>
</marquee>
This is the HTML for the marquee. it holds a paragraph element that has an id (you can name it anything as long as it has one for the javascript)
<li><button value="0" title="Crumblin Down - John Mellencamp" onclick="playsong()">crumblin_down.mp3
<audio><source src="https://media-upload.net/uploads/5S9FeDnNyrOE.mp3" type="audio/mp3"></audio>
</button></li >
Here is a list item again. I used title=""
to store the text i want the marquee to display (song title and artist). you dont have to do this if what you want to display is the same as the text inside the list element
function playsong() {
document.getElementById('marq').innerHTML = event.target.title;}
function stopmusic() {
document.getElementById('marq').innerHTML = 'no music is playing';}
Here are the two javascript functions we made earlier, each with an extra line for the marquee
document.getElementById('marq').innerHTML
this selects the text inside of the element we gave the #marq idevent.target.title
- this identifies the title attribute of the clicked song button, thus making the marquee display the title text of the clicked song- if you want to make the marque display the same text as the list element, use
event.target.innerHTML
- if you want to make the marque display the same text as the list element, use
- the marquee text in the stop music function does not depend on song, so we can use plain text for the message
there is one more thing to add
var y = document.getElementsByTagName('audio');
for(var j=0; j<y.length; j++) {
y[j].onended = function() {
document.getElementById('marq').innerHTML = 'select a song!';};}
without this bit of javascript, the marquee would continue to display a songs name after the song finished on its own (the marquee so far only changes when a different song is chosen, or the stop button is clicked)
- this code does not go in either function, rather it sets up an additional unnamed function
- it is important to note that this function is not an onclick function, infact it doesnt require any user input
- instead it makes a function for what happens when an audio element has reached the end of its content
- first the audio elements are identified similarly to how we pause the music
- but instead of pausing y[j] (the audio elements) we make a function for what happens when they end (
.onended
) - the function is the same as the other lines that alter the inner HTML of the #marq element, except I repeated the text that displays before a song is chosen, to indicate the song has ended and the user can select another song
- note: this function may not work if it is in the head of the html document. I ended up putting mine in a separate script tag in my .jukebox div after the songs
Thats it! Have fun ^^