Stackbits is going through a refresh! Some features may not be available. Follow @stackbitss on twitter for updates.
Cards > Skeumorphic Music Card

🎵 Skeumorphic Music Card

The Skeumorphic Music Card is a stylish React.js + Tailwind CSS music player with realistic shadows, beveled edges, and tactile buttons. Featuring play, pause, skip, and progress tracking, it's perfect for music apps, audio players, or portfolio projects. 🎵✨

Preview

Sideline

Sideline

David Dallas

Follow below steps 👇🏻

Install dependencies

npm i lucide-react

Component

Create a file skeumorphic-music-card.tsx in your components folder and paste this code

'use client'; import { Play, Pause, SkipForward, SkipBack } from 'lucide-react'; import { useState } from 'react'; interface SkeumorphicMusicCardProps { title: string; artist: string; cover: string; className?: string; } const ControlButton = ({ isPressed, onMouseDown, onMouseUp, onMouseLeave, onTouchStart, onTouchEnd, onClick, children, size = 'small' }: { isPressed: boolean; onMouseDown: () => void; onMouseUp: () => void; onMouseLeave: () => void; onTouchStart: () => void; onTouchEnd: () => void; onClick?: () => void; children: React.ReactNode; size?: 'small' | 'large'; }) => ( <div className="rounded-full p-[3px] border-[1px] border-black/5" style={{ background: 'linear-gradient(135deg, #c2d9f0 0%, #e6f0fa 100%)', boxShadow: 'inset 1px 1px 2px rgba(255,255,255,0.6), inset -1px -1px 2px rgba(0,0,0,0.1)' }} > <button onClick={onClick} onMouseDown={onMouseDown} onMouseUp={onMouseUp} onMouseLeave={onMouseLeave} onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} style={{ boxShadow: isPressed ? 'inset 3px 3px 7px rgba(0,0,0,0.2), inset -1px -1px 3px rgba(255,255,255,0.5)' : '-3px -3px 7px rgba(255,255,255,0.7), 3px 3px 7px rgba(0,0,0,0.2)', background: isPressed ? 'linear-gradient(135deg, #c2d9f0 0%, #d9e6f2 100%)' : 'linear-gradient(135deg, #e6f0fa 0%, #c2d9f0 100%)', transform: isPressed ? 'scale(0.95)' : 'scale(1)' }} className={`rounded-full transition-all duration-75 text-gray-700 hover:text-gray-900 ${ size === 'large' ? 'p-4' : 'p-2' }`} > {children} </button> </div> ); const ProgressBar = () => ( <div style={{ boxShadow: 'inset 2px 2px 3px rgba(0,0,0,0.1), inset -1px -1px 3px rgba(255,255,255,0.7)', background: 'linear-gradient(135deg, #c2d9f0 0%, #d9e6f2 100%)' }} className="h-2 rounded-full overflow-hidden" > <div style={{ width: '35%', background: 'linear-gradient(135deg, #6fa8dc 0%, #3d85c6 100%)', boxShadow: '1px 1px 2px rgba(255,255,255,0.3)' }} className="h-full rounded-full" /> </div> ); const SkeumorphicMusicCard = ({ title, artist, cover, className }: SkeumorphicMusicCardProps) => { const [isPlaying, setIsPlaying] = useState(false); const [isPlayButtonPressed, setIsPlayButtonPressed] = useState(false); const [isBackButtonPressed, setIsBackButtonPressed] = useState(false); const [isForwardButtonPressed, setIsForwardButtonPressed] = useState(false); const togglePlayPause = () => setIsPlaying(!isPlaying); return ( <div style={{ boxShadow: 'inset -8px -8px 15px rgba(255,255,255,0.8), inset 8px 8px 15px rgba(0,0,0,0.2)', background: 'linear-gradient(135deg, #e6ecf0 0%, #cfd8e2 100%)' }} className={`p-5 rounded-[30px] border-[1px] border-black/5 ${className}`} > <div style={{ boxShadow: 'inset 2px 2px 5px rgba(255,255,255,0.7), inset -2px -2px 5px rgba(0,0,0,0.1), 5px 5px 15px rgba(0,0,0,0.1)', background: 'linear-gradient(135deg, #e6f0fa 0%, #c2d9f0 100%)' }} className="relative w-80 p-6 rounded-[20px] flex flex-col items-center border-[1px] border-black/5" > {/* Album Cover */} <div style={{ boxShadow: '-2px -2px 5px rgba(255,255,255,0.5), 5px 5px 15px rgba(0,0,0,0.3)' }} className="w-40 h-40 rounded-xl overflow-hidden" > <img src={cover} alt={title} className="w-full h-full object-cover" /> </div> {/* Song Info */} <div className="mt-6 text-center"> <h3 className="text-lg font-semibold text-gray-800">{title}</h3> <p className="text-sm text-gray-600">{artist}</p> </div> <div className="w-full mt-6 px-2"> <ProgressBar /> </div> {/* Controls */} <div className="flex items-center justify-center gap-5 w-full px-2 mt-3"> <ControlButton isPressed={isBackButtonPressed} onMouseDown={() => setIsBackButtonPressed(true)} onMouseUp={() => setIsBackButtonPressed(false)} onMouseLeave={() => setIsBackButtonPressed(false)} onTouchStart={() => setIsBackButtonPressed(true)} onTouchEnd={() => setIsBackButtonPressed(false)} > <SkipBack size={22} /> </ControlButton> <ControlButton isPressed={isPlayButtonPressed} onMouseDown={() => setIsPlayButtonPressed(true)} onMouseUp={() => setIsPlayButtonPressed(false)} onMouseLeave={() => setIsPlayButtonPressed(false)} onTouchStart={() => setIsPlayButtonPressed(true)} onTouchEnd={() => setIsPlayButtonPressed(false)} onClick={togglePlayPause} size="large" > {isPlaying ? <Pause size={24} /> : <Play size={24} />} </ControlButton> <ControlButton isPressed={isForwardButtonPressed} onMouseDown={() => setIsForwardButtonPressed(true)} onMouseUp={() => setIsForwardButtonPressed(false)} onMouseLeave={() => setIsForwardButtonPressed(false)} onTouchStart={() => setIsForwardButtonPressed(true)} onTouchEnd={() => setIsForwardButtonPressed(false)} > <SkipForward size={22} /> </ControlButton> </div> </div> </div> ); }; export default SkeumorphicMusicCard;

Usage

<SkeumorphicMusicCard title="Sideline" artist="David Dallas" cover="https://t2.genius.com/unsafe/680x680/https%3A%2F%2Fimages.genius.com%2Fcd9ba63203bb2d02e141581abf7beeb7.640x640x1.jpg" />