Open In App

Create a Lyrics Search App in HTML CSS & JavaScript

Last Updated : 21 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

A Lyrics Search Application contains an input field, which takes the input as Song Name or Artist Name. Once the user enters the search query, the API Request is made to lyrics.ovh, and then the response is retrieved with the first 5 songs list of the search query. Users can view the lyrics of any of the songs which have been retrieved as a response.

Preview Image:

Screenshot-2024-02-14-at-20-24-49-GeeksforGeeks-Lyrics-Searcher

Prerequisites:

Approach:

  • Create the Lyrics Search App UI Structure using HTML Elements like <div>, <h1>, <input>, and <button>. Embed all the essential CDN links for external Fonts, Icons, etc.
  • When the entire structure of the application is designed, then using CSS styling properties like box-shadow, padding, width, overflow, etc. style the application.
  • Create transition effects, animations, loading spinner effects using keyframes, and more stying properties.
  • In the JavaScript file, specify the API URL in the variable, retrieve the input element value, and validate the query with basic validation.
  • Send the Request to the API and display the first 5 results of the search query. Using the innerHTML property, dynamically display the Lyrics and other information.

Project Structure:

1

Example: This example describes the basic implementation for a Lyrics Search App in HTML, CSS & JavaScript.

Javascript




const apiURL = 'https://api.lyrics.ovh';
document.getElementById('searchBtn')
.addEventListener('click', () => {
    const searchInput = document
    .getElementById('searchInput').value;
 
    if (searchInput !== '') {
        showLoading();
        seachFn(searchInput);
    } else {
        alert('Please enter a song or artist name.');
    }
});
document.getElementById('clearBtn').
addEventListener('click', () => {
    document.getElementById('searchInput').value = '';
    document.getElementById('results').innerHTML = '';
});
document.getElementById('results')
.addEventListener('click', (event) => {
    const target = event.target;
    if (target.classList.contains('back-btn')) {
        showResFn();
    } else if (target.classList
    .contains('lyrics-btn')) {
        const artist = target
        .getAttribute('data-artist');
        const title = target
        .getAttribute('data-title');
        apiGetFn(artist, title);
    }
});
function seachFn(query) {
    fetch(`${apiURL}/suggest/${query}`)
        .then(response => response.json())
        .then(data => showFn(data))
        .finally(() => loadFn());
}
function showFn(data) {
    const resultsContainer = document
    .getElementById('results');
    resultsContainer.innerHTML = '';
 
    if (data.total > 0) {
        data.data.slice(0, 6).forEach(song => {
            const card = document.createElement('div');
            card.classList.add('animate__animated',
            'animate__fadeIn', 'result-card');
 
            card.innerHTML = `
                <h3>${song.title}</h3>
                <p>${song.artist.name}</p>
                <button class="lyrics-btn"
                data-artist="${song.artist.name}"
                data-title="${song.title}">
                Get Lyrics
                </button>
                <button class="back-btn"
                style="display: none;">Back</button>
            `;
 
            resultsContainer.appendChild(card);
        });
    } else {
        resultsContainer.innerHTML =
        '<p>No results found.</p>';
    }
}
function apiGetFn(artist, title) {
    showLoading();
    const encodedTitle = encodeURIComponent(title);
    fetch(`${apiURL}/v1/${artist}/${encodedTitle}`)
        .then(response => response.json())
        .then(data => disResFn(data, title, artist))
        .finally(() => loadFn());
}
function disResFn(data, title, artist) {
    const resultsContainer = document
    .getElementById('results');
    resultsContainer.innerHTML = '';
 
    const resCard = document
    .createElement('div');
    resCard.classList.add
    ('
    animate__animated',
    'animate__fadeIn', '
    result-card'
    );
 
    if (data.lyrics) {
        resCard.innerHTML = `
            <h3>${title}</h3>
            <p>${artist}</p>
            <div class="lyrics-container">
            ${formatFn(data.lyrics)}</div>
            <button class="back-btn">Back</button>
        `;
        bckFn(resCard);
    } else {
        resCard.innerHTML =
        '<p>No lyrics found for this song.</p>';
    }
    resultsContainer
    .appendChild(resCard);
}
function formatFn(lyrics) {
    return lyrics.split('\n').map(line => `<p>${line}</p>`)
    .join('');
}
function showLoading() {
    document.getElementById('loadingContainer')
    .style.display = 'flex';
}
function loadFn() {
    document.getElementById('loadingContainer')
    .style.display = 'none';
}
function bckFn(card) {
    const bckBtn = card.querySelector('.back-btn');
    bckBtn.style.display = 'block';
}
function showResFn() {
    const resCon = document
    .getElementById('results');
    resCon.innerHTML = '';
    seachFn(document
    .getElementById('searchInput').value);
}


HTML




<!-- index.html -->
<!DOCTYPE html>
<head>
    <link rel="stylesheet"
          href=
    <link rel="stylesheet"
          href=
    <link href=
          rel="stylesheet">
    <link rel="stylesheet"
          href="styles.css">
    <title>GeeksforGeeks Lyrics Searcher</title>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1 class="animate__animated animate__fadeInDown"
                style="color: green;">
              GeeksforGeeks Lyrics Searcher
              </h1>
        </div>
        <div class="search-container">
            <i class="fas fa-music"
               style="color: #e74c3c;">
              </i>
            <input type="text"
                   id="searchInput"
                   placeholder="Search for lyrics"
                   style="background: #ecf0f1; color: #333;">
            <button id="searchBtn"
                    style="background: #2ecc71; color: #fff;">
                           earch
              </button>
            <button id="clearBtn"
                     
                    style="background: #e74c3c; color: #fff;">
                             Clear
              </button>
        </div>
        <div class="result-container" id="results"></div>
    </div>
    <div class="loading-container" id="loadingContainer">
        <div class="loading-spinner"
             style="border-color: #3498db;
                    border-top-color: #e74c3c;"></div>
    </div>
    <script src="app.js"></script>
</body>
</html>


CSS




body {
    margin: 0;
    padding: 0;
    font-family: 'Montserrat', sans-serif;
    background: linear-gradient(to right, #3494E6, #EC6EAD);
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
}
.container {
    background: rgba(255, 255, 255, 0.8);
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
    max-width: 600px;
    width: 100%;
    overflow: hidden;
}
.header {
    text-align: center;
    margin-bottom: 20px;
}
.search-container {
    display: flex;
    align-items: center;
    gap: 10px;
}
i {
    font-size: 24px;
    color: #333;
}
input {
    flex: 1;
    padding: 10px;
    font-size: 16px;
    border: none;
    border-radius: 5px;
    border: 2px solid #e5e90c;
}
button {
    padding: 10px 20px;
    font-size: 16px;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}
#searchBtn {
    background: #2ecc71;
    color: #fff;
}
#searchBtn:hover {
    background: #27ae60;
}
#clearBtn {
    background: #e74c3c;
    color: #fff;
}
#clearBtn:hover {
    background: #c0392b;
}
.result-container {
    margin-top: 20px;
    max-height: 600px;
    overflow-y: auto;
}
.result-card {
    margin-bottom: 20px;
    background: #fff;
    border-radius: 10px;
    padding: 20px;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
    transition: transform 0.3s ease-in-out;
    position: relative;
}
.result-card:hover {
    transform: scale(1.03);
}
.result-card h3 {
    margin-bottom: 5px;
}
.lyrics-container {
    white-space: pre-wrap;
    font-size: 16px;
    color: #333;
}
.loading-container {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(255, 255, 255, 0.8);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    display: none;
}
.loading-spinner {
    border: 5px solid #3498db;
    border-radius: 50%;
    border-top: 5px solid #e74c3c;
    width: 50px;
    height: 50px;
    animation: spin 1s linear infinite;
}
@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}
#backBtn {
    position: absolute;
    top: 20px;
    left: 20px;
    background: #3498db;
    color: #fff;
    border: none;
    padding: 10px 20px;
    font-size: 16px;
    cursor: pointer;
    z-index: 1000;
}
#backBtn:hover {
    background: #2980b9;
}


Output:

Output



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads