The Experience component displays professional work history in a Spotify playlist-inspired design with interactive playback-style controls.
Overview
Location: src/app/components/sections/ExperienceItems.tsx
This component mimics a Spotify playlist interface to present professional experience in an engaging, familiar format. It features playlist-style controls and a scrollable list of positions.
Implementation
export default function ExperienceItem() {
return (
<section
className="relative col-span-2 row-span-4 col-start-3 bg-spotify-light-dark rounded-xl max-md:overflow-y-scroll overflow-hidden max-md:col-span-1"
id="experience"
>
<div className="bg-spotify-gray px-6 py-4">
<h2 className="text-xl font-semibold mb-1">Professional Experience</h2>
<p className="flex items-center gap-1.5 text-spotify-grey text-sm">
<CiGlobe className="text-lg" />
8 positions • 3+ internship experience
</p>
</div>
<div className="px-4 py-3">
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<button
className="rounded-full bg-spotify-green p-3.5 hover:scale-105 transition-transform"
aria-label="Play experience showcase"
>
<FaPlay className="text-spotify-black text-sm" />
</button>
<div className="flex items-center gap-5">
<button aria-label="Shuffle experiences">
<IoShuffle className="text-3xl text-spotify-grey sm:hover:text-white transition-colors" />
</button>
<button aria-label="Add to favorites">
<FiPlusCircle className="text-2xl text-spotify-grey sm:hover:text-white transition-colors" />
</button>
<button aria-label="Download resume">
<MdOutlineDownloadForOffline className="text-2xl text-spotify-grey sm:hover:text-white transition-colors" />
</button>
<button aria-label="More options">
<BsThreeDots className="text-2xl text-spotify-grey sm:hover:text-white transition-colors" />
</button>
</div>
</div>
<button aria-label="View list">
<RxHamburgerMenu className="text-2xl text-spotify-grey sm:hover:text-white transition-colors" />
</button>
</div>
</div>
<Positions />
</section>
);
}
Features
The header displays aggregate experience statistics:
<div className="bg-spotify-gray px-6 py-4">
<h2 className="text-xl font-semibold mb-1">Professional Experience</h2>
<p className="flex items-center gap-1.5 text-spotify-grey text-sm">
<CiGlobe className="text-lg" />
8 positions • 3+ internship experience
</p>
</div>
Section heading: “Professional Experience”
Total positions count and internship experience summary
Playback Controls
Spotify-style controls for thematic consistency:
While styled as playback controls, these buttons serve as decorative UI elements that reinforce the Spotify theme.
<button
className="rounded-full bg-spotify-green p-3.5 hover:scale-105 transition-transform"
aria-label="Play experience showcase"
>
<FaPlay className="text-spotify-black text-sm" />
</button>
- Prominent Spotify-green circular button
- Scales up on hover for interactive feedback
Secondary Controls
<div className="flex items-center gap-5">
<button aria-label="Shuffle experiences">
<IoShuffle className="text-3xl text-spotify-grey sm:hover:text-white transition-colors" />
</button>
<button aria-label="Add to favorites">
<FiPlusCircle className="text-2xl text-spotify-grey sm:hover:text-white transition-colors" />
</button>
<button aria-label="Download resume">
<MdOutlineDownloadForOffline className="text-2xl text-spotify-grey sm:hover:text-white transition-colors" />
</button>
<button aria-label="More options">
<BsThreeDots className="text-2xl text-spotify-grey sm:hover:text-white transition-colors" />
</button>
</div>
Control icons:
- Shuffle (
IoShuffle): Randomize order
- Plus (
FiPlusCircle): Add to favorites
- Download (
MdOutlineDownloadForOffline): Download resume
- More (
BsThreeDots): Additional options
All control buttons include hover effects that change color from grey to white, matching Spotify’s interaction patterns.
Positions Component
Implementation
function Positions() {
return (
<div className="px-4 pb-4 md:overflow-y-auto sm:h-[300px]">
{experienceLists.map((position: experienceListsProps, index: number) => (
<div
className="flex items-center gap-4 p-2.5 sm:hover:bg-[#282828] rounded-lg transition-colors group"
key={position.companyName}
>
<span className="text-spotify-grey sm:group-hover:text-white min-w-[20px]">
{index + 1}
</span>
<div className="flex flex-col gap-0.5">
<a
href={position.url}
target="_blank"
rel="noopener noreferrer"
className="text-spotify-green text-sm font-semibold mb-0.5 bg-spotify-green/20 rounded-md transition-all duration-200 w-fit px-2 py-0.5 hover:bg-spotify-green/10 cursor-pointer"
>
{position.companyName}
</a>
<p className="font-bold text-md mb-0.5">{position.positionTitle}</p>
<p className="text-spotify-gray text-sm">{position.date}</p>
</div>
</div>
))}
</div>
);
}
Position Data Structure
Experience data is imported from a centralized data file:
import {
experienceLists,
experienceListsProps,
} from "../../../../data/experience";
Company or organization name
Position Row Layout
Each position displays as a numbered row:
<div className="flex items-center gap-4 p-2.5 sm:hover:bg-[#282828] rounded-lg transition-colors group">
{/* Index number */}
<span className="text-spotify-grey sm:group-hover:text-white min-w-[20px]">
{index + 1}
</span>
{/* Position details */}
<div className="flex flex-col gap-0.5">
<a href={position.url} target="_blank" rel="noopener noreferrer">
{position.companyName}
</a>
<p className="font-bold">{position.positionTitle}</p>
<p className="text-spotify-gray text-sm">{position.date}</p>
</div>
</div>
Interactive Elements
Row Hover Effect
sm:hover:bg-[#282828] /* Background changes on hover */
group /* Enables child element coordination */
When hovering over a row:
- Background color darkens
- Index number changes from grey to white
Company Link Styling
<a
className="text-spotify-green text-sm font-semibold mb-0.5 bg-spotify-green/20 rounded-md transition-all duration-200 w-fit px-2 py-0.5 hover:bg-spotify-green/10 cursor-pointer"
href={position.url}
target="_blank"
rel="noopener noreferrer"
>
{position.companyName}
</a>
Company names are displayed as badges with Spotify-green text on a semi-transparent background, creating visual hierarchy.
Grid Layout
Desktop Layout
.experience-item {
grid-column: span 2; /* Takes 2 columns */
grid-row: span 4; /* Takes 4 rows */
grid-column-start: 3; /* Starts at column 3 */
}
Mobile Responsive
- Mobile: Single column (
max-md:col-span-1)
- Scrolling: Mobile uses
overflow-y-scroll, desktop uses fixed height with scrollable content area
- Height: Content area fixed at
sm:h-[300px] for consistent scrolling
Styling Details
Color Scheme
/* Header background */
bg-spotify-gray /* #282828 */
/* Card background */
bg-spotify-light-dark /* #121212 */
/* Text colors */
text-spotify-grey /* #B3B3B3 - for metadata */
text-spotify-green /* #1DB954 - for company names */
text-white /* Primary text */
/* Hover states */
hover:text-white /* Control buttons on hover */
hover:bg-[#282828] /* Row background on hover */
Spacing and Layout
- Header padding:
px-6 py-4
- Controls padding:
px-4 py-3
- Positions padding:
px-4 pb-4
- Row padding:
p-2.5
- Gap between controls:
gap-5
- Gap in position details:
gap-0.5
Fixed height container with scrollable positions list:md:overflow-y-auto sm:h-[300px]
Entire component becomes scrollable:
Accessibility
- Semantic HTML with
<section> for the main container
- ARIA labels for all interactive buttons:
- “Play experience showcase”
- “Shuffle experiences”
- “Add to favorites”
- “Download resume”
- “More options”
- “View list”
- External links include
rel="noopener noreferrer" for security
- Proper heading hierarchy (
<h2> for section title)
Dependencies
{
"react-icons/ci": "CiGlobe",
"react-icons/io5": "IoShuffle",
"react-icons/fi": "FiPlusCircle",
"react-icons/md": "MdOutlineDownloadForOffline",
"react-icons/bs": "BsThreeDots",
"react-icons/rx": "RxHamburgerMenu",
"react-icons/fa": "FaPlay"
}
Experience data is externalized in data/experience.ts for easy maintenance and updates without modifying component code.