Music Player Card — Free HTML CSS JS Snippet

Music Player Card · Cards · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Vinyl CSS spin animation: @keyframes rotate(360deg) 4s linear infinite
animation-play-state toggled via .spinning class — paused vs running
classList.toggle("spinning", playing) — two-argument force form
Play/pause SVG icon swap via innerHTML replacement — no dual-element show/hide
Next/prev track with modulo wraparound: (idx + 1) % tracks.length
load(i) updates track name, artist, duration, and progress from tracks array
setInterval() simulates progress; clearInterval() on pause
Export as HTML file, React JSX, or React + Tailwind CSS
Mobile (375px), Tablet (768px), Desktop device preview buttons
Live split-pane editor — preview updates as you type

About this UI Snippet

Music Player Card — Vinyl Spin Animation, Play/Pause State & Track Switching

Screenshot of the Music Player Card snippet rendered live

A music player UI card demonstrates several important interactive patterns: a toggle between two states (play/pause), cycling through an array of items (tracks), animated visual feedback (vinyl spin), and a progress bar. These patterns appear in audio players, video players, carousels, and any queue-based interface. This snippet implements the full player UI without the Web Audio API — it simulates playback with a timer.

The tracks data structure

The tracks array contains objects with name, artist, dur (duration string), and pct (simulated progress percentage). The load(i) function reads these values and updates the DOM elements with querySelector and textContent.

The vinyl spin animation

The vinyl disc uses a CSS @keyframes spin animation: transform: rotate(360deg) at 4s linear infinite. The vinyl starts with animation-play-state: paused. The .spinning class changes it to running. togglePlay() calls vinyl.classList.toggle('spinning', playing) — which adds .spinning when playing is true and removes it when false. This is the classList.toggle(name, force) two-argument form, where force controls whether to add or remove.

The play/pause SVG icon swap

document.getElementById('play-icon').innerHTML is set to a pause icon SVG on play and a play icon SVG on pause. The inner HTML assignment replaces the entire SVG content, swapping from a triangle (play) to two rectangles (pause). This avoids two separate icon elements that need to be shown/hidden.

Track switching

next() increments idx modulo tracks.length for wraparound, then calls load(idx). prev() decrements similarly. The load() function updates all DOM elements from the new track object.

Simulated progress

A setInterval() timer in togglePlay() increments the progress bar fill by 0.5% every 100ms when playing. Pausing clears the interval. This simulates progress without the Web Audio API. Replace with a real <audio> element's timeupdate event to wire real playback.

The vinyl spin animation

The vinyl record uses animation: spin 3s linear infinite with animation-play-state: paused initially. On play, animation-play-state changes to running; on pause, back to paused. This approach correctly resumes from the current rotation angle rather than jumping back to 0° — which would happen if the animation were added and removed from the classList. The vinyl inner detail (the label and ring) uses a second element that counter-rotates at a slower rate for visual depth.

The progress bar interaction

The progress bar background is a range input with -webkit-appearance: none for cross-browser custom styling. Its value tracks the current time percentage. Clicking the bar sets currentTime = (e.offsetX / bar.offsetWidth) * duration. A setInterval updates the bar value every 250ms while the track plays.

Track switching

An array holds the track objects (title, artist, duration). The previous/next buttons decrement/increment the track index with wrapping. switchTrack() updates the title, artist, duration display, resets the progress bar to 0, and either plays immediately or stays paused depending on the current playback state.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Rather than tracing the fake-playback timer by hand, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why the vinyl uses animation-play-state toggled by a class instead of adding and removing the animation itself, and what visual bug that difference prevents when you pause partway through a spin. The same assistant can help optimize it, for instance asking whether the setInterval-driven tick() firing every second and mutating style.width directly could be replaced with something that degrades more gracefully if the tab is backgrounded, or how the whole simulated-progress system would need to change to wire in a real audio element's timeupdate event. It's also useful for extending the player: ask it to add a real shuffle mode that randomizes play order instead of just decorating the button, implement the currently cosmetic volume slider so it actually affects a real audio element, or add a queue/playlist panel that lists all tracks with the current one highlighted. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a "music player card" UI in plain HTML, CSS, and JavaScript that simulates playback without the Web Audio API or a real audio element — no external audio library.

Requirements:
- A card showing a square album-art area with a continuously animated background gradient, a smaller circular "vinyl" disc centered on it that only spins while a track is playing (using CSS animation-play-state toggled between paused and running, not by adding/removing the animation itself, so a pause preserves the current rotation angle rather than resetting it).
- Track metadata (name, artist, duration) driven from an array of track objects; a like/heart button that toggles a filled state independent of playback.
- A clickable progress bar/track showing elapsed percentage with a draggable-looking thumb; clicking anywhere on it must jump the fill to that horizontal position proportionally.
- A play/pause button whose icon swaps between a play triangle and a pause icon by replacing the inner SVG markup (not by showing/hiding two separate icon elements), and which starts/stops a timer that simulates progress advancing over time, updating both the fill width and a formatted mm:ss elapsed-time label derived from the track's total duration.
- Previous/next buttons that move to another track in the array with wraparound at both ends (so next from the last track goes to the first, and vice versa), reloading that track's name, artist, duration, and initial progress into the DOM.
- A volume slider that is present and styled but whose input is currently a no-op, structured so it's obvious where real volume-control logic would be wired in.
- Add a code comment describing exactly what would change if this were wired to a real audio element instead of the simulated timer (which event to listen to, and which property replaces the manual percentage math).

Step by step

How to Use

  1. 1
    Interact with the playerClick play to start the vinyl spin and progress. Click prev/next to switch tracks. Click pause to stop. The volume slider is purely visual.
  2. 2
    Update the tracks arrayIn the JS panel, update the tracks array with your song names, artists, and durations. The pct field sets the initial progress bar position.
  3. 3
    Wire to a real audio elementAdd an <audio> element to the HTML. In togglePlay(), call audio.play() or audio.pause(). Replace the timer with audio.addEventListener("timeupdate") to update the progress bar from audio.currentTime.
  4. 4
    Change the vinyl gradientIn the CSS panel, update the background gradient on .vinyl to change the disc colour.
  5. 5
    Add a like button or shuffleCopy a control button from the .controls row and add an onclick to toggle a .liked class or randomise the track index.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.

Real-world uses

Common Use Cases

Podcast and audio player widgets
Use as the UI for an embedded podcast player. Wire to the Web Audio API or an <audio> element — replace the setInterval timer with the timeupdate event listener.
Portfolio background music player
Add an ambient music player to a creative portfolio. The dark card and vinyl aesthetic match developer and designer portfolio aesthetics.
Learn play-state animation and toggle patterns
The vinyl uses animation-play-state toggled via classList. The icon swaps via innerHTML. Edit both in the panels to understand these patterns.
Prototype media player interactions
Use as a prototype to test track switching UX, progress bar behaviour, and control placement before building a full audio player.
Wire to a real <audio> element
Add <audio src="your-file.mp3" id="audio"> to HTML. Replace togglePlay() timer with audio.play()/pause(). Use timeupdate to update the fill width from audio.currentTime / audio.duration.
Music streaming service card UI
Use as a now-playing widget in a music streaming UI. The track array structure maps directly to a playlist API response with name, artist, and duration fields.

Got questions?

Frequently Asked Questions

The vinyl has animation-play-state: paused by default — the spin animation exists but is frozen. The .spinning class changes it to running. classList.toggle("spinning", playing) adds .spinning when playing is true and removes it when false.

document.getElementById("play-icon").innerHTML is set to a pause SVG (two rectangles) when playing, or a play SVG (triangle path) when paused. This replaces the entire SVG content rather than showing and hiding separate elements.

next() sets idx = (idx + 1) % tracks.length for modulo wraparound and calls load(idx). load() reads the tracks[i] object and updates the DOM: .track-name textContent, .artist textContent, the duration span, and the fill width.

Add <audio id="audio" src="your-file.mp3"> to the HTML. In togglePlay(), replace the setInterval timer with audio.play() or audio.pause(). Add audio.addEventListener("timeupdate", () => { fill.style.width = (audio.currentTime / audio.duration * 100) + "%"; }) for real progress.

Add objects to the tracks array in the JS panel: { name: "Song Name", artist: "Artist", dur: "3:45", pct: 0 }. The prev/next modulo arithmetic handles any number of tracks automatically.

Yes. Click "JSX" for a React component. In React, manage idx and playing as useState. Use useRef for the vinyl element to toggle the spinning class. Wire a useEffect to handle the setInterval timer, cleaning it up on pause or unmount.