Overview
The music search feature allows users to search for songs by querying the MYMUSICK backend API. The search is triggered by pressing Enter in the search input field, and results are dynamically rendered as interactive cards.
The search interface is located in the header with an accessible, styled input field:
< input id = "searchInput"
class = "search"
type = "search"
placeholder = "Busca tu Música 🎵"
aria-label = "Buscar canciones" >
The search input features an elegant design with focus animations:
.search {
width : 250 px ;
padding : 12 px 15 px ;
border-radius : 20 px ;
border : 2 px solid var ( --accent );
background : black ;
color : white ;
font-size : 16 px ;
outline : none ;
transition : 0.3 s ease ;
}
.search:focus {
width : 280 px ;
box-shadow : 0 0 10 px rgba ( 255 , 87 , 87 , 0.5 );
}
The search input expands from 250px to 280px on focus and adds a red glow effect for better user experience.
API Integration
The search functionality connects to the MYMUSICK backend API hosted on Render:
input . addEventListener ( "keydown" , async ( e ) => {
if ( e . key !== "Enter" ) return ;
const query = input . value . trim ();
if ( ! query ) return ;
results . innerHTML = `<p>Buscando... 🎵</p>` ;
try {
const res = await fetch (
`https://mymusick-backend.onrender.com/search?q= ${ encodeURIComponent ( query ) } `
);
if ( ! res . ok ) throw new Error ();
const songs = await res . json ();
renderSongs ( songs );
} catch {
results . innerHTML = `<p>Error al buscar 😕</p>` ;
}
});
API Endpoint
Request Format
Response Format
GET https://mymusick-backend.onrender.com/search?q={query}
The query parameter is encoded using encodeURIComponent() to ensure special characters are properly handled.
Rendering Search Results
The renderSongs() function dynamically creates song cards from the API response:
function renderSongs ( songs ) {
results . innerHTML = "" ;
if ( ! songs ?. length ) {
results . innerHTML = `<p>No se encontraron resultados</p>` ;
return ;
}
songs . forEach ( song => {
const div = document . createElement ( "div" );
div . className = "song" ;
div . tabIndex = 0 ;
div . innerHTML = `
<img src=" ${ song . thumbnail } "
alt="Portada de ${ song . title } "
loading="lazy"
crossorigin="anonymous">
<div class="song-info">
<strong> ${ song . title } </strong>
<small> ${ song . artist } </small>
</div>
` ;
div . addEventListener ( "mouseenter" , () => detectarColor ( song . thumbnail , div ));
div . addEventListener ( "mouseleave" , () => div . style . background = "" );
div . addEventListener ( "click" , () => loadSong ( song ));
div . addEventListener ( "keydown" , e => {
if ( e . key === "Enter" ) loadSong ( song );
});
results . appendChild ( div );
});
}
Song Card Structure
Each song card includes:
Thumbnail image with lazy loading and CORS support
Title displayed in bold
Artist name in smaller, gray text
Interactive events for hover, click, and keyboard navigation
Song Card Styling
estilooriginal.css:190-236
.song {
min-width : 160 px ;
padding : 12 px ;
background : var ( --bg-dark );
border-radius : 15 px ;
border : 1 px solid transparent ;
display : flex ;
flex-direction : column ;
gap : 6 px ;
cursor : pointer ;
scroll-snap-align : start ;
transition : 0.2 s ease ;
}
.song:hover {
background : #1e1e1e ;
border-color : var ( --accent );
transform : translateY ( -6 px );
}
.song img {
width : 100 % ;
aspect-ratio : 1 / 1 ;
border-radius : 12 px ;
object-fit : cover ;
}
Song cards feature a smooth lift animation on hover (translateY(-6px)) and dynamic background coloring based on the thumbnail’s dominant color.
Results Container
The results are displayed in a horizontally scrollable container:
estilooriginal.css:162-185
#results {
margin-left : 200 px ;
padding : 20 px ;
min-height : 400 px ;
display : flex ;
gap : 20 px ;
overflow-x : auto ;
scroll-snap-type : x mandatory ;
scroll-behavior : smooth ;
align-items : flex-start ;
}
#results::-webkit-scrollbar {
height : 8 px ;
}
#results::-webkit-scrollbar-thumb {
background : var ( --accent );
border-radius : 4 px ;
}
#results::-webkit-scrollbar-track {
background : var ( --bg-dark );
}
Usage Example
Complete Search Flow Example
User types “rock music” in the search input
User presses Enter
Loading message displays: “Buscando… 🎵”
API request is sent to https://mymusick-backend.onrender.com/search?q=rock%20music
Response contains array of song objects
renderSongs() creates interactive cards for each song
User hovers over a card → dominant color extraction triggers
User clicks a card → song loads in the YouTube player
Accessibility Features
Semantic HTML : Uses <input type="search"> with proper aria-label
Keyboard Navigation : Song cards are focusable with tabIndex={0}
Enter Key Support : Songs can be played by pressing Enter when focused
Alt Text : All images include descriptive alt attributes
Error Handling
The search implementation includes robust error handling:
try {
const res = await fetch ( /* API URL */ );
if ( ! res . ok ) throw new Error ();
const songs = await res . json ();
renderSongs ( songs );
} catch {
results . innerHTML = `<p>Error al buscar 😕</p>` ;
}
If the API request fails or returns a non-OK status, users see a friendly error message instead of a blank screen.
YouTube Player Learn how selected songs are played using the YouTube IFrame API
Dynamic Theming Discover how dominant colors are extracted from thumbnails