I recently completed a project that I am excited to share an “Expense Tracker” built using HTML, CSS, and JavaScript. It’s a functional and visually appealing app that helps users manage their finances by tracking income and expenses. In this blog, I’ll explain how I developed this project step by step, including the code and solutions to common challenges.
Why an Expense Tracker?
As someone passionate about building projects that solve real-life problems, I wanted to create an application that simplifies personal finance management. An expense tracker is a perfect tool for this. It allows users to:
- Add income and expense transactions.
- See their current balance.
- View a transaction history.
This project was also an excellent opportunity to work on core web development skills, including form handling, DOM manipulation, and event handling in JavaScript.
Features of the Expense Tracker
- Real-Time Balance Updates:
- Displays the total balance dynamically as users add income or expenses.
- Transaction History:
- Logs every transaction, showing the description and amount.
- Interactive Interface:
- Uses a form to add transactions and update the display instantly.
- Clear Separation of Income and Expenses:
- Tracks and categorizes transactions into income and expenses.
How I Built It
HTML Structure
The HTML structure serves as the skeleton of the app. Here’s the code I used:
code<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Expense Tracker</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>Expense Tracker</h1>
<div class="balance">
<h2>Your Balance</h2>
<h3 id="balance">$0.00</h3>
</div>
<div class="income-expense">
<div class="income">
<h3>Income</h3>
<p id="income-amount">$0.00</p>
</div>
<div class="expense">
<h3>Expenses</h3>
<p id="expense-amount">$0.00</p>
</div>
</div>
<h3>History</h3>
<ul id="transaction-list" class="history"></ul>
<h3>Add New Transaction</h3>
<form id="transaction-form">
<input type="text" id="description" placeholder="Enter description" required>
<input type="number" id="amount" placeholder="Enter amount" required>
<button type="submit">Add Transaction</button>
</form>
</div>
<script src="script.js"></script>
</body>
</html>
Styling with CSS
CSS brought the interface to life, making it visually appealing and user-friendly. Here’s the CSS I used:
codebody {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
background: #fff;
padding: 20px;
width: 300px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
text-align: center;
}
h1 {
margin-bottom: 20px;
}
.balance h2, .balance h3 {
margin: 5px 0;
}
.income-expense {
display: flex;
justify-content: space-between;
margin: 20px 0;
}
.income, .expense {
width: 45%;
}
.income h3, .expense h3 {
margin: 0;
color: green;
}
.expense h3 {
color: red;
}
form {
display: flex;
flex-direction: column;
}
form input, form button {
margin: 5px 0;
padding: 10px;
}
button {
background-color: #007bff;
color: #fff;
border: none;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
JavaScript Logic
The JavaScript file handles all the functionality, including form submission, updating the balance, and rendering transaction history.
code// Select DOM elements
const balanceEl = document.getElementById('balance');
const incomeEl = document.getElementById('income-amount');
const expenseEl = document.getElementById('expense-amount');
const transactionList = document.getElementById('transaction-list');
const form = document.getElementById('transaction-form');
const descriptionInput = document.getElementById('description');
const amountInput = document.getElementById('amount');
// Transaction data
let transactions = [];
// Add a new transaction
function addTransaction(e) {
e.preventDefault();
const description = descriptionInput.value;
const amount = parseFloat(amountInput.value);
if (description.trim() === '' || isNaN(amount)) return alert('Please provide valid inputs.');
const transaction = {
id: Date.now(),
description,
amount
};
transactions.push(transaction);
updateUI();
form.reset();
}
// Update the UI
function updateUI() {
// Calculate totals
const income = transactions
.filter(t => t.amount > 0)
.reduce((sum, t) => sum + t.amount, 0);
const expenses = transactions
.filter(t => t.amount < 0)
.reduce((sum, t) => sum + Math.abs(t.amount), 0);
// Update DOM
balanceEl.textContent = `$${(income - expenses).toFixed(2)}`;
incomeEl.textContent = `$${income.toFixed(2)}`;
expenseEl.textContent = `$${expenses.toFixed(2)}`;
// Render transaction history
transactionList.innerHTML = '';
transactions.forEach(t => {
const li = document.createElement('li');
li.textContent = `${t.description}: $${t.amount.toFixed(2)}`;
li.classList.add(t.amount > 0 ? 'income' : 'expense');
transactionList.appendChild(li);
});
}
// Event listener
form.addEventListener('submit', addTransaction);
Challenges and Solutions
- Dynamic Updates:
- Challenge: Keeping the balance, income, and expense totals updated dynamically.
- Solution: I used JavaScript functions to recalculate these values each time a transaction was added or removed.
- Form Validation:
- Challenge: Preventing invalid inputs.
- Solution: Added input validation to ensure all required fields are filled and the amount is a valid number.
- Transaction History Rendering:
- Challenge: Updating the transaction list without refreshing the page.
- Solution: Used DOM manipulation to render transactions dynamically.
Explanation
This expense tracker is more than just a coding exercise it’s a practical tool. It helps users manage their finances in a simple and intuitive way. For clients, it’s a great example of how custom web applications can solve real-life problems effectively.
Final Thoughts
Building this expense tracker allowed me to blend HTML, CSS, and JavaScript into a cohesive, functional project. It was a rewarding experience, and the end result is something I’m proud to share.