PROJECT REPORT – “Indian Food Recipes” Web Application
The Indian Food Recipes project is a fully responsive and interactive web application
designed using HTML, CSS, and JavaScript. The primary objective of the application is to
display popular Indian recipes in an engaging and easy-to-navigate format. The website also
includes several interactive features such as category-based navigation, recipe detail
toggling, a feedback form with validation, and a light/dark mode toggle that remembers the
user’s preference. The entire application runs without external frameworks, ensuring
lightweight performance and maximum compatibility.
When the page first loads, the application checks the browser’s localStorage to see if the
user has previously selected dark mode. If dark mode was enabled in a past session, the site
immediately applies the .dark class to the element and changes the theme without any
flicker. Next, the navigation menu is dynamically built from a categories array, which contains
items like “All,” “North Indian,” “South Indian,” “Snacks,” and “Feedback.” Each button in this
menu is created by JavaScript and styled so that the currently active category is visually
highlighted. This “active state” helps users know exactly which section they are browsing.
The core content of the site is generated from a JavaScript array of recipe objects. Each
recipe object contains the name, category, description, image path, ingredients, and
preparation steps. When a category is selected, the program filters the recipes by their
category property and displays only the matching recipes. If “All” is selected, all recipe cards
are shown. These cards are displayed using a CSS Grid layout, which automatically adjusts
the number of columns depending on the screen size. This ensures that the site is responsive
and works seamlessly on both desktop and mobile devices.
Each recipe card contains an image, title, short description, and a “Show Recipe” button.
Clicking this button reveals the ingredients list and the cooking steps for that dish. This is
handled by the toggleDetails() function, which simply switches the display style of the details
section between block and none. This keeps the interface clean by hiding long instructions
until they are needed. CSS styling such as box shadows, rounded corners, and hover effects
makes these cards visually appealing and easy to read.
One of the major features of the application is the Feedback Form. When the user clicks the
“Feedback” category in the navigation menu, the recipe list is replaced with a form. The
form includes input fields for the user’s name, email address, a dropdown rating, and a
message textarea. When the form is submitted, JavaScript validation checks that the name is
at least two characters long, the email contains an “@” symbol, and the message has at least
five characters. If any check fails, the user is alerted to correct their input. If all checks pass,
the feedback is stored in localStorage under the key feedback. This means that even if the
user reloads or closes the page, their feedback remains saved in the browser. Below the
form, all stored feedback entries are displayed dynamically, each showing the name, rating,
and message.
The Light/Dark Mode Toggle is another key interactive feature. A circular button fixed at the
bottom-right corner of the screen allows the user to switch between light mode and dark
mode instantly. When clicked, the dark class is toggled on the element, which changes
background colors, text colors, and card colors according to the CSS rules defined for dark
mode. The button’s icon also changes between ■ and ■■ to indicate the current mode. The
choice is saved in localStorage so that on future visits, the user sees the same theme they
last used.
Stylistically, the site uses Flexbox for the navigation bar, allowing the buttons to wrap neatly
on smaller screens, and CSS Grid for the recipe display to make the layout flexible and
adaptive. The visual design includes gradients for the header background, subtle hover
animations on cards, and consistent padding and margins to create a balanced layout. The
overall user experience is designed to be simple yet functional, with clear visual cues for
interaction. This project effectively demonstrates dynamic content rendering, state
management with localStorage, and responsive design techniques without relying on
external libraries. The clear separation of concerns—HTML for structure, CSS for styling, and
JavaScript for behavior—makes the code maintainable and easy to enhance. Possible
improvements could include adding a search bar to filter recipes by keyword, replacing the
rating dropdown with clickable star ratings, and hosting all images locally for complete
offline compatibility.
In conclusion, the Indian Food Recipes web application is a compact yet feature-rich project
that fulfills all the required criteria: project planning, responsive layout, active navigation
state, dynamic recipe cards, validated form with persistent storage, and a customizable
theme. It offers a practical example of how pure HTML, CSS, and JavaScript can be used to
build a polished, interactive, and responsive web application from scratch.
WEBSITE’s CODE
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title> Indian Recipes</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
background: #fafafa;
color: #333;
transition: background 0.3s, color 0.3s;
header {
background: linear-gradient(45deg, orange, tomato);
padding: 15px;
color: white;
text-align: center;
nav {
display: flex;
justify-content: center;
gap: 10px;
flex-wrap: wrap;
margin-top: 10px;
nav button {
background: white;
color: tomato;
border: none;
padding: 8px 15px;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
nav button.active {
background: tomato;
color: white;
.recipes-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
padding: 20px;
.recipe {
background: white;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
overflow: hidden;
transition: transform 0.2s;
}
.recipe:hover {
transform: translateY(-4px);
.recipe img {
width: 100%;
height: 180px;
object-fit: cover;
.recipe-content {
padding: 15px;
.details {
display: none;
margin-top: 10px;
button.show-btn {
background: orange;
color: white;
border: none;
padding: 6px 10px;
margin-top: 8px;
border-radius: 5px;
cursor: pointer;
form {
background: white;
max-width: 500px;
margin: 20px auto;
padding: 15px;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
input, textarea, select {
width: 100%;
margin-bottom: 10px;
padding: 8px;
border: 1px solid #ccc;
border-radius: 5px;
#darkToggle {
position: fixed;
bottom: 20px;
right: 20px;
background: orange;
color: white;
border: none;
width: 50px;
height: 50px;
border-radius: 50%;
font-size: 20px;
cursor: pointer;
.dark {
background: #1e1e1e;
color: white;
}
.dark .recipe {
background: #2a2a2a;
.dark form {
background: #2a2a2a;
.feedback-item {
background: #fff;
padding: 10px;
margin-top: 10px;
border-radius: 5px;
.dark .feedback-item {
background: #2a2a2a;
</style>
</head>
<body>
<header>
<h1> Indian Food Recipes</h1>
<nav id="navMenu"></nav>
</header>
<div id="content"></div>
<button id="darkToggle"> </button>
<script>
const recipes = [
name: "Butter Chicken",
category: "North Indian",
desc: "Creamy tomato chicken curry.",
img: "/images/butter chicken.jpg",
ingredients: ["Chicken", "Tomato sauce", "Cream", "Spices"],
steps: ["Cook chicken", "Add sauce", "Add cream"]
},
name: "Vegetable Biryani",
category: "North Indian",
desc: "Fragrant rice with vegetables.",
img: "/images/vegb.jpeg",
ingredients: ["Rice", "Vegetables", "Spices"],
steps: ["Cook rice", "Cook veggies", "Mix together"]
},
name: "Masala Dosa",
category: "South Indian",
desc: "Crispy pancake with potato filling.",
img: "/images/md.jpeg",
ingredients: ["Dosa batter", "Potatoes", "Onion", "Spices"],
steps: ["Cook potatoes", "Make dosa", "Add filling"]
},
name: "Chole (Chickpea Curry)",
category: "North Indian",
desc: "Spicy chickpea curry.",
img: "/images/chole.jpg",
ingredients: ["Chickpeas", "Onions", "Tomatoes", "Spices"],
steps: ["Cook onions", "Add tomatoes", "Add chickpeas"]
},
name: "Samosa",
category: "Snacks",
desc: "Crispy snack with potato filling.",
img: "/images/samosa.jpg",
ingredients: ["Flour", "Potatoes", "Peas", "Spices"],
steps: ["Make dough", "Add filling", "Fry until golden"]
];
const categories = ["All", "North Indian", "South Indian", "Snacks", "Feedback"];
let currentCategory = "All";
function buildNav() {
const navMenu = document.getElementById("navMenu");
navMenu.innerHTML = categories.map(cat =>
`<button class="${cat === currentCategory ? 'active' : ''}"
onclick="changeCategory('${cat}')">${cat}</button>`
).join("");
function changeCategory(cat) {
currentCategory = cat;
buildNav();
if (cat === "Feedback") {
showFeedbackForm();
} else {
showRecipes();
function showRecipes() {
let filtered = currentCategory === "All" ? recipes : recipes.filter(r => r.category ===
currentCategory);
document.getElementById("content").innerHTML = `
<div class="recipes-container">
${filtered.map((r, i) => `
<div class="recipe">
<img src="${r.img}" alt="${r.name}">
<div class="recipe-content">
<h3>${r.name}</h3>
<p>${r.desc}</p>
<button class="show-btn" onclick="toggleDetails(${i})">Show
Recipe</button>
<div class="details" id="details-${i}">
<h4>Ingredients</h4>
<ul>${r.ingredients.map(item => `<li>${item}</li>`).join("")}</ul>
<h4>Steps</h4>
<ol>${r.steps.map(step => `<li>${step}</li>`).join("")}</ol>
</div>
</div>
</div>
`).join("")}
</div>
`;
function toggleDetails(i) {
const el = document.getElementById(`details-${i}`);
el.style.display = el.style.display === "block" ? "none" : "block";
function showFeedbackForm() {
const storedFeedback = JSON.parse(localStorage.getItem("feedback") || "[]");
document.getElementById("content").innerHTML = `
<form onsubmit="return submitFeedback()">
<input type="text" id="name" placeholder="Your Name" required>
<input type="email" id="email" placeholder="Your Email" required>
<select id="rating" required>
<option value="">Rate Us</option>
<option>5 - Amazing!</option>
<option>4 - Good</option>
<option>3 - Okay</option>
<option>2 - Bad</option>
<option>1 - Terrible</option>
</select>
<textarea id="message" placeholder="Your feedback..." required></textarea>
<button type="submit" class="show-btn">Send</button>
</form>
<div id="feedbackList">
${storedFeedback.map(f => `
<div class="feedback-item">
<strong>${f.name}</strong> (${f.rating})<br>${f.message}
</div>
`).join("")}
</div>
`;
function submitFeedback() {
const name = document.getElementById("name").value.trim();
const email = document.getElementById("email").value.trim();
const rating = document.getElementById("rating").value;
const message = document.getElementById("message").value.trim();
if (name.length < 2 || !email.includes("@") || message.length < 5) {
alert("Please fill all fields correctly.");
return false;
const feedback = JSON.parse(localStorage.getItem("feedback") || "[]");
feedback.unshift({ name, email, rating, message });
localStorage.setItem("feedback", JSON.stringify(feedback));
showFeedbackForm();
return false;
const darkToggle = document.getElementById("darkToggle");
darkToggle.addEventListener("click", () => {
document.body.classList.toggle("dark");
localStorage.setItem("darkMode", document.body.classList.contains("dark"));
darkToggle.textContent = document.body.classList.contains("dark") ? " ":" ";
});
function loadDarkMode() {
if (localStorage.getItem("darkMode") === "true") {
document.body.classList.add("dark");
darkToggle.textContent = " ";
// Init
loadDarkMode();
buildNav();
showRecipes();
</script>
</body>
</html>
Screenshots