Ever wanted to build your own music player like Spotify? This project shows how to create a Spotify Clone Music Player using only HTML, CSS, and JavaScript.
This project includes:
-
🎧 Play, pause, and next/previous track controls
-
🎼 Progress bar & seek functionality
-
🎨 Stylish Spotify-inspired UI
-
📱 Fully responsive for mobile & desktop
Why this project?
Music players are a perfect way to learn JavaScript events, DOM manipulation, and audio handling. By building this Spotify Clone, you’ll not only sharpen your coding skills but also end up with a project that looks cool in your portfolio.
You can customize it with your own playlist, album covers, or themes to make it unique.
Do check out the video tutorial of this project on my YouTube channel and do subscribe to support me! Thanks!
Here’s the HTML/CSS/JS code for the project 👇
<!-- Created by CodingPorium,2025. Visit https://youtube.com/c/CodingPorium for more tutorials with free source code --> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Spotify Clone - Local Music Player | CodingPorium</title> <!-- Import Poppins Font --> <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet"> <style> /* Colors and Variables */ :root{ --bg:#121212; --panel:#181818; --muted:#9a9a9a; --accent:#1db954; } /* Global Styles */ *{ box-sizing: border-box; } body{ margin: 0; font-family: poppins,sans-serif; background: var(--bg); color:#fff; } /* Layout */ .app{ display: flex; height: calc(100vh - 90px); /*leaving some space for controls*/ } /* Sidebar */ .sidebar{ width:220px; padding:20px; background: #000; } .sidebar h1{ margin: 0 0 20px; color: var(--accent); } .sidebar .tip{ margin-top:20px; font-size: 13px; color:var(--muted); } /* Main Section */ .main{ flex:1; padding: 20px; overflow-y: auto; } .top-bar{ display: flex; justify-content: space-between; align-items: center; } .playlist{ margin-top:10px; } .song-item{ padding: 10px; margin:6px 0; border-radius:6px; background: #282828; cursor: pointer; display: flex; justify-content: space-between; align-items: center; } .song-item:hover{ background: #333; } .song-item.active{ background: var(--accent); color:#000; } .empty{ padding: 10px; color: var(--muted); } /* Controls */ .controls{ position: fixed; bottom:0; left:0; right:0; height: 90px; padding:0 20px; background: var(--panel); display: flex; align-items: center; justify-content: space-between; } .controls .left{ display: flex; align-items: center; gap:12px; min-width:220px; } .controls button{ background: none; border:none; color: #fff; font-size: 20px; cursor: pointer; padding: 8px; } /* Progress bar */ #progress-container{ width:400px; height:6px; margin-left: 12px; background: #222; border-radius: 6px; cursor: pointer; overflow: hidden; } #progress{ width:0%; height:100%; background: var(--accent); } .times{ font-size: 12px; color: var(--muted); margin-left: 8px; } /* Buttons */ .btn{ font-family: poppins; padding:8px 12px; border: none; border-radius: 6px; cursor:pointer; background:var(--accent); color:#000; } .btn.clear{ background: #444; color:#fff; } /* Hide file input */ input[type="file"]{display: none;} /* Responsive */ @media (max-width:700px){ .sidebar{display: none} #progress-container{width:200px;} } </style> </head> <body> <div class="app"> <!-- Sidebar --> <div class="sidebar"> <h1>Spotify</h1> <div style="color:var(--muted)">Local Songs Player</div> <div class="tip">Use the "Choose Files" button to load songs in mp3 form</div> </div> <!-- Main content --> <div class="main"> <div class="top-bar"> <h2>Playlist</h2> <div class="top-actions"> <label for="file-input" class="btn">Choose Files</label> <input id="file-input" type="file" accept="audio/*" multiple> <button id="clear-btn" class="btn clear">Clear</button> </div> </div> <div class="playlist" id="playlist"> <div class="empty"> No songs loaded - add files using the button above. </div> </div> </div> </div> <!-- Controls --> <div class="controls"> <div class="left"> <div> <div id="song-title">No Song</div> <div style="display:flex;align-items:center;margin-top:8px;"> <button id="prev">⏮</button> <button id="play">▶</button> <button id="next">⏭</button> <div id="progress-container"> <div id="progress"></div> </div> <div class="times"> <span id="time-current">0:00</span> / <span id="time-total">0:00</span> </div> </div> </div> </div> <div style="color:var(--muted)">Local player - files stay on your device</div> <audio id="audio"></audio> </div> <script> /* Select elements */ const fileInput=document.getElementById('file-input'); const playlistDiv = document.getElementById('playlist'); const audio = document.getElementById('audio'); const playBtn = document.getElementById('play'); const prevBtn = document.getElementById('prev'); const nextBtn = document.getElementById('next'); const titleDiv = document.getElementById('song-title'); const progressEl = document.getElementById('progress'); const progressContainer = document.getElementById('progress-container'); const timeCurrent = document.getElementById('time-current'); const timeTotal = document.getElementById('time-total'); const clearBtn = document.getElementById('clear-btn'); /* Player state */ let songs = []; // Stores {title, url, file} let songIndex = 0;// Current song index let isPlaying = false; /* Helper : format time */ function formatTime(sec){ if(!sec || isNaN(sec)) return '0:00'; const m = Math.floor(sec / 60); const s = Math.floor(sec % 60).toString().padStart(2,'0'); return `${m}:${s}`; } /* Reset UI if no songs loaded */ function showNoSongs(){ playlistDiv.innerHTML='<div class="empty">No songs loaded - add files using the button above.</div>'; titleDiv.textContent = 'No song'; timeCurrent.textContent = '0:00'; timeTotal.textContent = '0:00'; progressEl.style.width = '0%'; audio.removeAttribute('src'); isPlaying = false; playBtn.textContent = '▶'; } /* Build playlist UI */ function loadPlaylistUI(){ playlistDiv.innerHTML = ''; if(!songs.length){showNoSongs();return;} songs.forEach((s,idx)=>{ const div =document.createElement('div'); div.className='song-item'; div.textContent= s.title; div.addEventListener('click',()=> playSong(idx)); playlistDiv.appendChild(div); }); updateActive(); } /* Highlight Active Song */ function updateActive(){ const items = playlistDiv.querySelectorAll('.song-item'); items.forEach((item,i)=> { item.classList.toggle('active',i===songIndex); }); } /* Load Files */ fileInput.addEventListener('change',(e)=>{ const files = Array.from(e.target.files).filter(f => f.type.startsWith('audio/')); if(!files.length){ alert('No audio files selected. Use mp3 or m4a.'); return; } // Clean old URLs songs.forEach(s=>{if (s.url.startsWith('blob:')) URL.revokeObjectURL(s.url);}); songs=files.map(f=>({title:f.name, url: URL.createObjectURL(f), file:f})); songIndex=0; loadPlaylistUI(); playSong(0); }); /* Play sleected song */ function playSong(index){ if(!songs.length)return; songIndex = index; audio.src = songs[songIndex].url; titleDiv.textContent = songs[songIndex].title; audio.play().then(() => { isPlaying=true; playBtn.textContent='⏸'; updateActive(); }).catch(err => { console.error('Playback failed: ',err); alert('Playback failed - check console for details') }); } /* Play/Pause */ playBtn.addEventListener('click',()=>{ if(!audio.src){alert('Load files first.');return;} if(isPlaying){ audio.pause(); playBtn.textContent = '▶'; }else{ audio.play().catch(e => console.error(e)); playBtn.textContent='⏸'; } isPlaying= !isPlaying; }); /* Prev / Next */ prevBtn.addEventListener('click',()=>{ if(!songs.length)return; songIndex=(songIndex - 1 +songs.length)% songs.length; playSong(songIndex); }); nextBtn.addEventListener('click',()=>{ if(!songs.length)return; songIndex=(songIndex + 1)% songs.length; playSong(songIndex); }); audio.addEventListener('ended',()=>nextBtn.click()); /* Progress bar update */ audio.addEventListener('timeupdate',()=>{ if(!isNaN(audio.duration)){ const pct = (audio.currentTime / audio.duration)*100; progressEl.style.width=pct + '%'; timeCurrent.textContent = formatTime(audio.currentTime); timeTotal.textContent = formatTime(audio.duration); } }); /* Seek song */ progressContainer.addEventListener('click',(e)=>{ if(!audio.duration)return; const rect = progressContainer.getBoundingClientRect(); const pct = (e.clientX - rect.left)/rect.width; audio.currentTime = pct*audio.duration; }); /* Clear Playlist */ clearBtn.addEventListener('click',()=>{ songs.forEach(s=> {if (s.url.startsWith('blob:')) URL.revokeObjectURL(s.url);}); songs=[]; fileInput.value=''; showNoSongs(); }) /* Cleanup */ window.addEventListener('beforeunload', ()=>{ songs.forEach(s => {if (s.url.startsWith('blob:')) URL.revokeObjectURL(s.url);}); }); // Initial state showNoSongs(); </script> </body> </html>
✨ With just a few lines of code, you’ve built your own functional Spotify Clone Music Player for this year! Keep practicing and soon you’ll be building bigger and more powerful projects.
Thanks for reading, do subscribe our YouTube channel to support us in providing more awesome projects with free source code!
Post a Comment