Expense Tracker with HTML, CSS & JavaScript

20 DAYS 20 PROJECT CHALLENGE

Day #07

Project Overview

A simple, clean Expense Tracker that lets users add income and expenses, store them permanently in LocalStorage, and automatically calculate totals using map() and reduce(). The tracker shows a running balance, separate income & expense totals, and lets you delete transactions.

This project teaches:

  • DOM manipulation

  • Array methods (map, filter, reduce)

  • LocalStorage (saving + loading persistent data)

  • Building reusable UI render functions

  • Handling form inputs and validation

Key Features

  • Add income (positive) or expense (negative).
  • Fully persistent using LocalStorage.
  • Summary section:
    • Total Balance
    • Total Income
    • Total Expense
  • Transaction history with:
    • Colored indicators (green for income, red for expense)
    • Delete button
  • Clean UI and responsive layout
  • Automatically recalculates totals after each change

HTML Code

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>Day 7 — Expense Tracker</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>

<main class="card">
  <header>
    <div class="logo">ET</div>
    <div>
      <h1>Day 7: Expense Tracker</h1>
      <p class="lead">Track income & expenses, view your balance, and store data using LocalStorage.</p>
    </div>
  </header>

  <!-- BALANCE SUMMARY -->
  <section class="summary">
    <div class="box">
      <h3>Balance</h3>
      <p id="balance" class="big">₹0</p>
    </div>

    <div class="box green">
      <h3>Income</h3>
      <p id="income">₹0</p>
    </div>

    <div class="box red">
      <h3>Expense</h3>
      <p id="expense">₹0</p>
    </div>
  </section>

  <!-- ADD TRANSACTION -->
  <section class="add">
    <h2>Add Transaction</h2>

    <label>
      <span>Description</span>
      <input id="desc" type="text" placeholder="e.g. Salary, Groceries" />
    </label>

    <label>
      <span>Amount (use - for expense)</span>
      <input id="amount" type="number" placeholder="e.g. 500 or -200" />
    </label>

    <button id="addBtn" class="btn">Add Transaction</button>
  </section>

  <!-- HISTORY -->
  <section>
    <h2>History</h2>
    <ul id="list" class="list"></ul>
  </section>

</main>

<script src="script.js"></script>
</body>
</html>

CSS Code

:root {
  --bg: #071026;
  --card: #0b1220;
  --muted: #9aa4b2;
  --green: #10b981;
  --red: #ef4444;
  --white: #e6eef6;
  font-family: Inter, system-ui, sans-serif;
}

body {
  margin: 0;
  background: #002252;
  color: var(--white);
  display: flex;
  justify-content: center;
  padding: 30px;
}

.card {
  width: min(650px, 100%);
  background: rgba(255,255,255,0.03);
  padding: 20px;
  border-radius: 14px;
  border: 1px solid rgba(255,255,255,0.05);
  box-shadow: 0 8px 30px rgba(0,0,0,0.5);
}

header {
  display: flex;
  align-items: center;
  gap: 15px;
}

.logo {
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: linear-gradient(135deg, #7c3aed, #22c1c3);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
}

.lead {
  color: var(--muted);
  margin-top: 4px;
  font-size: 14px;
}

.summary {
  display: flex;
  justify-content: space-between;
  margin-top: 20px;
  gap: 15px;
}

.box {
  flex: 1;
  padding: 15px;
  border-radius: 10px;
  background: rgba(255,255,255,0.05);
  text-align: center;
}

.box.green {
  border-left: 4px solid var(--green);
}

.box.red {
  border-left: 4px solid var(--red);
}

.big {
  font-size: 26px;
  font-weight: 700;
}

.add {
  margin-top: 25px;
}

label {
  display: block;
  margin: 12px 0;
}

label span {
  display: block;
  margin-bottom: 5px;
  color: var(--muted);
}

input {
  width: 100%;
  padding: 10px;
  background: transparent;
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 8px;
  color: var(--white);
  outline: none;
}

.btn {
  width: 100%;
  margin-top: 10px;
  padding: 12px;
  background: linear-gradient(90deg, #7c3aed, #22c1c3);
  border: 0;
  border-radius: 10px;
  font-weight: 600;
  color: white;
  cursor: pointer;
}

.list {
  margin-top: 15px;
  padding: 0;
  list-style: none;
}

.list li {
  display: flex;
  justify-content: space-between;
  background: rgba(255,255,255,0.04);
  border-left: 4px solid;
  padding: 12px;
  margin: 8px 0;
  border-radius: 8px;
  align-items: center;
}

.list .text {
  flex: 1;
  margin-left: 8px;
}

.list .amount.green {
  color: var(--green);
  font-weight: 700;
}

.list .amount.red {
  color: var(--red);
  font-weight: 700;
}

.del-btn {
  background: transparent;
  border: 0;
  color: var(--muted);
  cursor: pointer;
  font-size: 18px;
}

Javascript Code

// Select elements
const desc = document.getElementById("desc");
const amount = document.getElementById("amount");
const addBtn = document.getElementById("addBtn");
const list = document.getElementById("list");

const balanceEl = document.getElementById("balance");
const incomeEl = document.getElementById("income");
const expenseEl = document.getElementById("expense");

// Load from LocalStorage or start empty
let transactions = JSON.parse(localStorage.getItem("transactions")) || [];

// Save to LocalStorage
function saveData() {
  localStorage.setItem("transactions", JSON.stringify(transactions));
}

// Format numbers as rupees
function formatMoney(n) {
  return "₹" + n.toLocaleString("en-IN");
}

// Render all items
function renderList() {
  list.innerHTML = "";

  transactions.forEach((t) => {
    const li = document.createElement("li");
    li.style.borderColor = t.amount > 0 ? "#10b981" : "#ef4444";

    li.innerHTML = `
      <span class="text">${t.desc}</span>
      <span class="amount ${t.amount > 0 ? "green" : "red"}">${formatMoney(t.amount)}</span>
      <button class="del-btn" onclick="deleteItem(${t.id})">✖</button>
    `;

    list.appendChild(li);
  });

  updateSummary();
}

// Update totals using reduce()
function updateSummary() {
  const amounts = transactions.map((t) => t.amount);

  const total = amounts.reduce((acc, v) => acc + v, 0);
  const income = amounts.filter((v) => v > 0).reduce((a, b) => a + b, 0);
  const expense = amounts.filter((v) => v < 0).reduce((a, b) => a + b, 0);

  balanceEl.textContent = formatMoney(total);
  incomeEl.textContent = formatMoney(income);
  expenseEl.textContent = formatMoney(expense);
}

// Add transaction
addBtn.addEventListener("click", () => {
  const d = desc.value.trim();
  const a = Number(amount.value);

  if (!d || !amount.value) {
    alert("Please enter both description and amount.");
    return;
  }

  const t = {
    id: Date.now(),
    desc: d,
    amount: a
  };

  transactions.push(t);
  saveData();
  renderList();

  desc.value = "";
  amount.value = "";
});

// Delete item
function deleteItem(id) {
  transactions = transactions.filter((t) => t.id !== id);
  saveData();
  renderList();
}

// INITIAL RENDER
renderList();
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Related Projects

Day 5 : Digital Piano

Play sound notes when user clicks keys or presses keyboard buttons.

Concepts: Audio API, keyboard events.

Day 9 : Flashcard Learning App

Create and flip flashcards to study and test your knowledge.

Concepts: DOM manipulation, CSS 3D effects, LocalStorage.

Day 10 : Typing Speed Test

Measures typing speed and accuracy.

Concepts: Timers, string comparison, event listeners.