🎧 Building a Neumorphic Music Player with Playlist & Navigation Using HTML, CSS & JavaScript
July 01, 20255 min read

🎧 Building a Neumorphic Music Player with Playlist & Navigation Using HTML, CSS & JavaScript

Web developmentJavaScriptCSS3JavaScript Projects
share this article on

A stylish Neumorphism-based music player built with HTML, CSS, and JavaScript. Features include playlist navigation, play/pause, next/prev, volume cycling, and a responsive UI with smooth transitions.

A sleek, modern music player with Neumorphism UI, featuring:

🗂️ Project Structure

music-player/

├── index.html
├── style.css
├── script.js
├── cover.jpg
└── music.mp3

🧩 HTML Code for Random Color Generator

The HTML file contains the main structure of the page, including the color display, dropdown, and buttons.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Neumorphic Music Player</title>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <div class="player-container">
    
    <!-- ✅ Now Playing Screen -->
    <div id="nowPlayingScreen" class="screen active">
      <div class="header">
        <button id="backToPlaylist" class="neumorphic">←</button>
        <h2 class="nowPlaying">Now Playing</h2>
         <button id="volumeCycleBtn" class="neumorphic">🔊</button>
      </div>

      <div class="cover">
        <img id="cover" src="cover1.jpg" alt="Album Cover" />
      </div>
      <h2 id="title"></h2>
      <h3 id="artist"></h3>

      <div class="progress-container">
        <span id="current-time">0:00</span>
        <input type="range" id="progress" value="0" />
        <span id="duration">0:00</span>
      </div>

      <audio id="audio" src="music1.mp3"></audio>

      <div class="controls">
        <button id="prev" class="neumorphic"><span>&#9664;&#9664;</span></button>
        <button id="play" class="neumorphic play"><span class="play-icon">&#9654;</span></button>
        <button id="next" class="neumorphic"><span>&#9654;&#9654;</span></button>
      </div>

    </div>

    <!-- ✅ Playlist Screen -->
    <div id="playlistScreen" class="screen">
      <div class="header">
        <h2>Playlist</h2>
          <button id="goToPlayer" class="neumorphic">→</button>
        </div>
      <ul id="playlist"></ul>
    </div>

  </div> <!-- END of .player-container -->

  <script src="script.js"></script>
</body>
</html>

🌈 CSS Code: Styling the Neumorphism Look

body {
  background: #1e1e2f;
  font-family: 'Segoe UI', sans-serif;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  color: #f0f0f0;
}

.player-container {
  background: #2a2a3b;
  box-shadow: 10px 10px 20px #181820, -10px -10px 20px #3a3a4f;
  border-radius: 30px;
  padding: 30px;
  width: 300px;
  text-align: center;
}

.cover img {
  width: 100%;
  border-radius: 20px;
  box-shadow: inset 6px 6px 12px #1e1e2a, inset -6px -6px 12px #3a3a4f;
}

h2, h3 {
  margin: 15px 0 5px;
  color: #ffffff;
  text-align: center;
}

.controls {
  display: flex;
  justify-content: space-around;
  margin: 20px 0;
}

.neumorphic {
  background: #2a2a3b;
  border: none;
  padding: 15px;
  border-radius: 20%;
  box-shadow: 6px 6px 12px #181820, -6px -6px 12px #3a3a4f;
  cursor: pointer;
  font-size: 18px;
  color: #ffffff;
}

.neumorphic span {
  font-style: normal;
}

.neumorphic:active {
  box-shadow: inset 4px 4px 8px #181820, inset -4px -4px 8px #3a3a4f;
}

.progress-container {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 20px 0 30px 0;
}

#progress {
  flex: 1;
  -webkit-appearance: none;
  height: 6px;
  border-radius: 4px;
  transition: background-size 0.1s linear;
  outline: none;
}

#progress::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #ffffff;
  cursor: pointer;
  box-shadow: 0 0 5px rgba(255, 255, 255, 0.6);
  border: none;
  margin-top: -3px; /* aligns it vertically with the bar */
}

#progress::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #ffffff;
  cursor: pointer;
  border: none;
  box-shadow: 0 0 5px rgba(255, 255, 255, 0.6);
}

.volume-container {
  margin-top: 15px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

#volume {
  width: 100px;
}

#volume::-webkit-slider-thumb {
  background: #f0f0f0;
}

#play.play {
  color: #fff; /* Green (you can switch to orange if preferred) */
  background: #20c997;
}

#progress::-webkit-slider-thumb,
#volume::-webkit-slider-thumb {
  background: #fff;
}

.screen {
  display: none;
  padding: 20px;
}

.screen.active {
  display: block;
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

#playlistScreen ul {
  list-style: none;
  padding: 0;
}

.playlist-item {
  display: flex;
  align-items: center;
  gap: 15px;
  padding: 10px 0;
  border-bottom: 1px solid #333;
}

.playlist-item img {
  width: 50px;
  height: 50px;
  object-fit: cover;
  border-radius: 8px;
}

.playlist-item .info {
  flex: 1;
}

.playlist-item button {
  background: #20c997;
  color: white;
  border: none;
  border-radius: 6px;
  padding: 6px 10px;
  cursor: pointer;
}

.header {
    margin-bottom: 20px;
}

.nowPlaying{
    font-size: 16px;
}

🎯 JavaScript Functionality

const songs = [
  {
    title: "Emotional Mess",
    artist: "Amy Lynn & the Honey Men",
    src: "music1.mp3",
    cover: "cover1.jpg"
  },
  {
    title: "Kung Fu Love Tree",
    artist: "Quincas Moreira",
    src: "music2.mp3",
    cover: "cover2.jpg"
  },
  {
    title: "Cottonmouth Strut",
    artist: "The Whole Other",
    src: "music3.mp3",
    cover: "cover3.jpg"
  },
    {
    title: "Emotional Mess",
    artist: "Amy Lynn & the Honey Men",
    src: "music1.mp3",
    cover: "cover1.jpg"
  },
  {
    title: "Kung Fu Love Tree",
    artist: "Quincas Moreira",
    src: "music2.mp3",
    cover: "cover2.jpg"
  },
  {
    title: "Cottonmouth Strut",
    artist: "The Whole Other",
    src: "music3.mp3",
    cover: "cover3.jpg"
  }
];

document.addEventListener("DOMContentLoaded", function() {
    
let songIndex = 0;

const audio = document.getElementById("audio");
const title = document.getElementById("title");
const artist = document.getElementById("artist");
const cover = document.getElementById("cover");
const playBtn = document.getElementById("play");
const prevBtn = document.getElementById("prev");
const nextBtn = document.getElementById("next");
const progress = document.getElementById("progress");
const currentTimeEl = document.getElementById("current-time");
const durationEl = document.getElementById("duration");
const volume = document.getElementById("volume");

window.loadSong = function (song) {
  title.textContent = song.title;
  artist.textContent = song.artist;
  audio.src = song.src;
  cover.src = song.cover;
}

window.playSong = function() {
  audio.play();
  playBtn.innerHTML = '<span class="pause-icon">❚❚</span>';
}

window.pauseSong = function() {
  audio.pause();
  playBtn.innerHTML = '<span class="play-icon">▶</span>';
}

window.togglePlay = function() {
  if (audio.paused) {
    window.playSong();
  } else {
    window.pauseSong();
  }
}

function prevSong() {
  const wasPlaying = !audio.paused;
  songIndex = (songIndex - 1 + songs.length) % songs.length;
  loadSong(songs[songIndex]);
  if (wasPlaying) playSong(); else pauseSong();
}

// Load initial song
window.loadSong(songs[songIndex]);

document.addEventListener('click', function(e) {
    if (
        e.target.tagName === 'BUTTON' && 
        e.target.classList.contains('btn-playlist') &&
        e.target.dataset.index
    ) {
        playFromPlaylist(e.target.dataset.index);
    }
})

function nextSong() {
  const wasPlaying = !audio.paused;
  songIndex = (songIndex + 1) % songs.length;
  loadSong(songs[songIndex]);
  if (wasPlaying) playSong(); else pauseSong();
}

const volumeSteps = [0.25, 0.5, 0.75, 1, 0]; // 0 is mute
let volumeIndex = 0;

document.getElementById("volumeCycleBtn").addEventListener("click", () => {
  volumeIndex = (volumeIndex + 1) % volumeSteps.length;
  const newVolume = volumeSteps[volumeIndex];
  audio.volume = newVolume;

  // Update volume icon
  const volumeIcon = document.getElementById("volumeCycleBtn");
  if (newVolume === 0) {
    volumeIcon.textContent = "🔇";
  } else if (newVolume <= 0.25) {
    volumeIcon.textContent = "🔈";
  } else if (newVolume <= 0.5) {
    volumeIcon.textContent = "🔉";
  } else {
    volumeIcon.textContent = "🔊";
  }
});


audio.addEventListener("loadedmetadata", () => {
  durationEl.textContent = formatTime(audio.duration);
});

function updateProgress() {
  const percent = (audio.currentTime / audio.duration) * 100;
  progress.value = percent || 0;
  currentTimeEl.textContent = formatTime(audio.currentTime);

  // Update background size to reflect progress visually
  progress.style.background = `linear-gradient(to right, #20c997 0%, #20c997 ${percent}%, #ccc ${percent}%, #ccc 100%)`;
}

function setProgress(e) {
  const percent = e.target.value;
  audio.currentTime = (percent / 100) * audio.duration;
}

function formatTime(time) {
  const mins = Math.floor(time / 60);
  const secs = Math.floor(time % 60).toString().padStart(2, '0');
  return `${mins}:${secs}`;
}

// Event listeners
playBtn.addEventListener("click", togglePlay);
prevBtn.addEventListener("click", prevSong);
nextBtn.addEventListener("click", nextSong);
audio.addEventListener("timeupdate", updateProgress);
progress.addEventListener("input", setProgress);
if (volume) {
    volume.addEventListener("input", (e) => {
        audio.volume = e.target.value;
    });
}
audio.addEventListener("ended", nextSong);


});

const playlistEl = document.getElementById("playlist");

for (let index = 0; index < songs.length; index++) {
    const song = songs[index];
    const li = document.createElement("li");
    li.classList.add("playlist-item");

    // Create elements manually instead of innerHTML
    const img = document.createElement("img");
    img.src = song.cover;
    img.alt = song.title;

    const infoDiv = document.createElement("div");
    infoDiv.classList.add("info");
    infoDiv.innerHTML = `<strong>${song.title}</strong><br><small>${song.artist}</small>`;

    const playButton = document.createElement("button");
    playButton.textContent = "▶";
    playButton.classList.add('btn-playlist');
    playButton.dataset.index = index;

    li.appendChild(img);
    li.appendChild(infoDiv);
    li.appendChild(playButton);
    playlistEl.appendChild(li);
}

// ✅ Fixed toggle here: Playlist to Now Playing
function playFromPlaylist(index) {
  songIndex = index;
  loadSong(songs[songIndex]);
  playSong();

  // Correct screen switch
  document.getElementById("playlistScreen").classList.remove("active");
  document.getElementById("nowPlayingScreen").classList.add("active");
}

// Navigate manually from Playlist to Now Playing
document.getElementById("goToPlayer").addEventListener("click", () => {
  document.getElementById("playlistScreen").classList.remove("active");
  document.getElementById("nowPlayingScreen").classList.add("active");
});

// Back button: Now Playing to Playlist
document.getElementById("backToPlaylist").addEventListener("click", () => {
    console.log("Back button clicked");
  document.getElementById("nowPlayingScreen").classList.remove("active");
  document.getElementById("playlistScreen").classList.add("active");
});

✅ Final Result


Back to Articles