Open In App

Design a Recipe App in HTML CSS & JavaScript

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

We will create an attractive and styled application that gives the recipe of food, and dishes entered by the user. The user needs to enter the required food name and click on the button. The application uses an External API to fetch the food recipe and represent it in an attractive form. The user can view the detailed Recipe of Dish in the modal component which makes the application more beautiful.

Prerequisites

Approach

  • Create an HTML file with all the essential UI structures of the application. Also, include all the external CDN links to use Fonts, Icons, Animation, etc.
  • By using the <div> with the class container to encapsulate all the card components into it. This includes an input field and buttons.
  • Once the structure is created, then we need to style the application using CSS styling properties. Some of the properties include font-family, flex-direction, etc.
  • In the main JavaScript file, we will define the external API link which gives the recipe data as per user search. The defaultFn() renders the recipe of the default search query which is directly passed in the code.
  • The searchFn() mainly sends the request to the API along with the search string and gets the response of a maximum of two recipes related to the search query. The showRecpsFn() is used to show the fetched recipe to the user in UI format.
  • There is modalFn() which is responsible for representing the complete recipe instructions in the modal form to the user.

Example: We will see the implementation of the above-explained approach.

Javascript




// script.js
const apiUrl =
    '...';
function defaultFn() {
    const defaultFood = 'chicken';
    searchFn(defaultFood);
}
document.getElementById('searchBtn')
    .addEventListener('click', () => {
        const userIn = document.getElementById('searchInput')
            .value.trim();
        if (userIn !== '') {
            searchFn(userIn);
        } else {
            alert('Please enter a recipe name.');
        }
    });
document.addEventListener('click', (event) => {
    if (event.target.className === 'show-recipe-btn') {
        const rId = event.target.getAttribute('data-id');
        modalFn(rId);
    }
    if (event.target.id === 'closeBtn') {
        closeModalFn();
    }
});
defaultFn();
function searchFn(query) {
    const url = `${apiUrl}${query}`;
    fetch(url)
        .then(res => res.json())
        .then(tmp => {
            if (tmp.meals) {
                showRecpsFn(tmp.meals);
            } else {
                noRecFn();
            }
        })
        .catch(error => console
            .error('Error fetching recipes:', error));
}
function showRecpsFn(r) {
    const rCont = document.getElementById('recipeContainer');
    rCont.innerHTML = '';
    r.slice(0, 20).forEach(recipe => {
        const c = document.createElement('div');
        c.classList.add('animate__animated',
            'animate__fadeIn', 'recipe-card');
        c.innerHTML = `
            <h3>${recipe.strMeal}</h3>
            <img src="${recipe.strMealThumb}"
            alt="${recipe.strMeal}">
            <p>${recipe.strArea}</p>
            <p>${recipe.strCategory}</p>
            <button class="show-recipe-btn"
             data-id="${recipe.idMeal}">Show Recipe</button>
        `;
 
        rCont.appendChild(c);
    });
    if (r.length === 1) {
        const card = rCont.firstChild;
        card.style.margin = 'auto';
    }
}
function noRecFn() {
    const rCont = document.getElementById('recipeContainer');
    rCont.innerHTML = '<p>No Recipe found</p>';
}
function modalFn(recipeId) {
    const mData = document.getElementById('modalContent');
    mData.innerHTML = '';
    fetch(`
...`)
        .then(response => response.json())
        .then(data => {
            const rep = data.meals[0];
            mData.innerHTML = `
                <h2>${rep.strMeal}</h2>
                <h3>Instructions:</h3>
                <p>${formatFn(rep.strInstructions)}</p>
            `;
            document.getElementById('recipeModal')
                .style.display = 'block';
        })
        .catch(error => console.error('Error fetching recipe details:',
            error));
}
function formatFn(instructions) {
    return instructions.split('\r\n').filter(instruction =>
        instruction.trim() !== '').join('<br>');
}
function closeModalFn() {
    document.getElementById('recipeModal').style.display = 'none';
}


HTML




<!DOCTYPE html>
<html lang="en">
 
<head>
    <link rel="stylesheet" href=
    <link rel="stylesheet" href=
    <link href=
    rel="stylesheet">
    <link rel="stylesheet" href="style.css">
    <title>GeeksforGeeks Recipe Application</title>
</head>
 
<body>
    <div class="container">
        <h1>GeeksforGeeks Recipe Application</h1>
        <div class="search-container">
            <i class="fas fa-search"></i>
            <input type="text" id="searchInput"
                   placeholder="Search for recipes">
            <button id="searchBtn">Search</button>
        </div>
        <div class="recipe-container" id="recipeContainer"></div>
    </div>
    <div class="modal" id="recipeModal">
        <div class="modal-content">
            <span class="close" id="closeBtn">×</span>
            <div id="modalContent"></div>
        </div>
    </div>
    <script src="script.js"></script>
</body>
 
</html>


CSS




body {
    margin: 0;
    padding: 0;
    font-family: 'Montserrat', sans-serif;
    background: linear-gradient(to right,
            #3494E6, #EC6EAD);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    overflow-x: hidden;
}
 
.container {
    background: rgba(255, 255, 255, 0.9);
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
    width: 100%;
    overflow: hidden;
    text-align: center;
    max-width: 1700px;
    margin: auto;
}
 
h1 {
    font-size: 24px;
    color: green;
    margin-bottom: 20px;
}
 
.search-container {
    display: flex;
    align-items: center;
    margin-bottom: 20px;
}
 
i {
    font-size: 24px;
    margin-right: 10px;
    color: #333;
}
 
input {
    flex: 1;
    padding: 10px;
    font-size: 16px;
    border: none;
    border-radius: 5px;
    border-color: #FF4848;
}
 
button {
    padding: 10px 20px;
    font-size: 16px;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    background: #FF4848;
    color: #fff;
}
 
#searchBtn:hover {
    background: #FF6565;
}
 
.recipe-container {
    display: grid;
    grid-template-columns: repeat(auto-fill,
            minmax(200px, 1fr));
    gap: 10px;
    max-width: 100%;
    overflow-y: auto;
    max-height: 70vh;
}
 
.recipe-card {
    background: linear-gradient(to right,
            #a0f8a4, rgb(160, 212, 255), 90%, 54%);
    border-radius: 20px;
    padding: 8px;
    box-shadow: 0 2px 5px rgb(255, 3, 3);
    transition: transform 0.3s ease-in-out;
    overflow: hidden;
    text-align: center;
}
 
.recipe-card:hover {
    transform: scale(1.03);
}
 
.recipe-card img {
    max-width: 70%;
    height: 40%;
    border-radius: 5px;
    margin-bottom: 10px;
}
 
.recipe-card h3 {
    margin-bottom: 5px;
    font-size: 14px;
}
 
.recipe-card p {
    font-size: 14px;
    color: rgb(0, 0, 0);
    margin-bottom: 10px;
}
 
.show-recipe-btn {
    background: #FF4848;
    color: #fff;
    padding: 8px;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    margin-top: 10px;
}
 
.show-recipe-btn:hover {
    background: #FF6565;
}
 
.modal {
    display: none;
    position: fixed;
    z-index: 1000;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
}
 
.modal-content {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: #fff;
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
    max-width: 400px;
    width: 100%;
}
 
.close {
    position: absolute;
    top: 10px;
    right: 10px;
    font-size: 20px;
    color: #555;
    cursor: pointer;
}
 
@media screen and (max-width: 600px) {
    .recipe-container {
        grid-template-columns: repeat(auto-fill,
                minmax(100%, 1fr));
    }
}
 
.search-container {
    display: flex;
    align-items: center;
    margin-bottom: 20px;
}
 
i {
    font-size: 24px;
    margin-right: 10px;
    color: #333;
}
 
input {
    flex: 1;
    padding: 10px;
    font-size: 16px;
    border: none;
    border-radius: 5px;
    border-color: #FF4848;
}
 
button {
    padding: 10px 20px;
    font-size: 16px;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    background: #FF4848;
    color: #fff;
}
 
#searchBtn:hover {
    background: #FF6565;
}
 
.recipe-container {
    display: grid;
    grid-template-columns: repeat(auto-fill,
            minmax(200px, 1fr));
    gap: 10px;
    max-width: 100%;
    overflow-y: auto;
    max-height: 70vh;
}
 
.recipe-card {
    background: linear-gradient(to right,
            #a0f8a4,
            rgb(160, 212, 255), 90%, 54%);
    border-radius: 20px;
    padding: 8px;
    box-shadow: 0 2px 5px rgb(255, 3, 3);
    transition: transform 0.3s ease-in-out;
    overflow: hidden;
    text-align: center;
}
 
.recipe-card:hover {
    transform: scale(1.03);
}
 
.recipe-card img {
    max-width: 70%;
    height: 40%;
    border-radius: 5px;
    margin-bottom: 10px;
}
 
.recipe-card h3 {
    margin-bottom: 5px;
    font-size: 14px;
}
 
.recipe-card p {
    font-size: 14px;
    color: rgb(0, 0, 0);
    margin-bottom: 10px;
}
 
.show-recipe-btn {
    background: #FF4848;
    color: #fff;
    padding: 8px;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    margin-top: 10px;
}
 
.show-recipe-btn:hover {
    background: #FF6565;
}
 
.modal {
    display: none;
    position: fixed;
    z-index: 1000;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
}
 
.modal-content {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: #fff;
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
    max-width: 400px;
    width: 100%;
}
 
.close {
    position: absolute;
    top: 10px;
    right: 10px;
    font-size: 20px;
    color: #555;
    cursor: pointer;
}
 
@media screen and (max-width: 600px) {
    .recipe-container {
        grid-template-columns: repeat(auto-fill,
                minmax(100%, 1fr));
    }
}


Output:



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads