Tip Calculator with HTML, CSS & JavaScript
20 DAYS 20 PROJECT CHALLENGE
Day #06
Project Overview
The Tip Calculator is a simple project that allows you to determine the amount of a tip for a particular bill. This Web application lets you know how much the bill will be with the tip and how much each person should pay if there are several people who want to split the payment. The project is built using HTML, CSS, and JavaScript.
It is easy to use and understand how the code works. Therefore, this project is helpful for beginners to see how much one can achieve by writing a small amount of code. Moreover, it can be used to practice working with HTML forms, mathematical calculations, working with variables, checking user input, and events in JavaScript, and the interaction between HTML, CSS, and JavaScript.
Key Features
- Bill Amount Input: The users can enter the desired amount that they wish to calculate. The amount acts as an input value that triggers the calculation of the tip and the final amount.
- Tip Percentage Selection: The application offers several percentages that the users can choose as a tip according to the quality of service. The selected percentage will determine the value of the tip.
- Tip Calculation: JavaScript performs the calculation of the tip using the previously entered values. The obtained value is dependent on the input values.
- Bill Splitting: The users have the option to enter the number of people that the bill is supposed to be divided among, and the calculated amount will be split accordingly.
- Amount Per Person: The amount that every person should pay is outlined in the Tip Calculator to help the users with splitting the bill.
- Dynamic Results: The calculated values update automatically depending on the user’s input and do not require any additional actions to be taken.
- Input Validation: JavaScript can check whether valid values have been entered before performing the calculation. This helps prevent incorrect or incomplete calculations.
- Simple and Clean Interface: The Tip Calculator uses a simple and intuitive design that is easy to understand and navigate.
- Responsive Design: The Tip Calculator is compatible with different devices and screen sizes and provides the optimal viewing and interaction experience.
- JavaScript-Based Calculations: The main functionality is handled using JavaScript, demonstrating how variables, user input, arithmetic operations, and DOM updates can create a practical web application.
What You’ll Learn
- Understand how HTML creates the structure of a calculator.
- Learn how JavaScript reads values from input fields.
- Practice converting user input into numbers.
- Understand how percentage calculations work in JavaScript.
- Learn how to perform arithmetic operations dynamically.
- Practice handling button click events.
- Understand how to validate user input before calculations.
- Learn how to update HTML elements with calculated results.
- Practice working with variables and mathematical operators.
HTML Code
The HTML code creates the structure of the Tip Calculator. It provides input fields where users can enter the bill amount and the number of people sharing the bill. A selection field or tip options allow users to choose the percentage that should be used for the tip calculation. The main calculator container keeps all the elements organized in one place. Separate elements are also provided for displaying the calculated tip amount and the amount each person needs to pay.
Finally, the CSS stylesheet is linked inside the <head> section so it can control the appearance of the application. The JavaScript file is loaded near the bottom of the <body> so the script can access the calculator elements and handle user interactions.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Day 6 — Tip Calculator</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<main class="card" role="main" aria-labelledby="title">
<header>
<div class="logo">TC</div>
<div>
<h1 id="title">Day 6: Tip Calculator</h1>
<p class="lead">Calculate tip per person and total per person quickly. Built with simple inputs and math logic.</p>
</div>
</header>
<section class="calc-grid">
<form id="tipForm" class="controls" novalidate>
<label>
Bill amount
<input id="bill" type="number" min="0" step="0.01" placeholder="0.00" inputmode="decimal" required>
</label>
<fieldset class="tip-buttons" aria-label="Tip percentage">
<legend>Select Tip %</legend>
<div class="buttons">
<button type="button" class="tipBtn" data-tip="5">5%</button>
<button type="button" class="tipBtn" data-tip="10">10%</button>
<button type="button" class="tipBtn" data-tip="15">15%</button>
<button type="button" class="tipBtn" data-tip="25">25%</button>
<button type="button" class="tipBtn" data-tip="50">50%</button>
<input id="customTip" type="number" min="0" step="1" placeholder="Custom" inputmode="numeric">
</div>
</fieldset>
<label>
Number of people
<input id="people" type="number" min="1" step="1" placeholder="1" inputmode="numeric" required>
</label>
<div class="form-actions">
<button id="resetBtn" type="button" class="btn secondary">Reset</button>
</div>
</form>
<aside class="results" aria-live="polite">
<div class="result-row">
<div class="label">Tip amount <span class="muted">/ person</span></div>
<div id="tipPerPerson" class="value">₹0.00</div>
</div>
<div class="result-row">
<div class="label">Total <span class="muted">/ person</span></div>
<div id="totalPerPerson" class="value">₹0.00</div>
</div>
<div id="error" class="error" aria-live="assertive"></div>
</aside>
</section>
<details style="margin-top:12px">
<summary>How it works (short)</summary>
<p class="small">JS reads bill, tip%, and people inputs, computes tip = bill * (tip%/100), tip per person = tip / people, total per person = (bill/people) + tip per person. Validation prevents division by zero and invalid input.</p>
</details>
</main>
<script src="script.js"></script>
</body>
</html>
CSS Code
The CSS code controls the appearance and layout of the Tip Calculator. It styles the main calculator container, headings, input fields, tip selection options, buttons, and result section. The main container uses properties such as padding, spacing, borders, rounded corners, and shadows to create a clean calculator interface. Input fields are styled to make entering values simple and readable, while the button receives separate styling so users can easily identify the action used to calculate the result.
The result section is also styled to clearly display the calculated amounts. In addition, responsive CSS can adjust the calculator layout and spacing on smaller screens, making the Tip Calculator easier to use on mobile devices.
:root {
--bg: #0f1724;
--card: #071027;
--accent: #7c3aed;
--muted: #9aa4b2;
--white: #e6eef6;
--danger: #ef4444;
font-family: Inter, system-ui, -apple-system, 'Segoe UI', Roboto, Arial;
}
html,
body {
height: 100%;
}
body {
margin: 0;
background: #002252;
color: var(--white);
display: flex;
align-items: center;
justify-content: center;
padding: 28px;
}
.card {
width: min(820px, 96%);
background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01));
border-radius: 12px;
padding: 18px;
box-shadow: 0 8px 30px rgba(2, 6, 23, 0.6);
border: 1px solid rgba(255, 255, 255, 0.03);
}
header {
display: flex;
gap: 14px;
align-items: center;
}
.logo {
width: 44px;
height: 44px;
border-radius: 10px;
background: linear-gradient(135deg, var(--accent), #22c1c3);
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
}
h1 {
margin: 0;
font-size: 18px;
}
.lead {
margin: 4px 0 12px;
color: var(--muted);
font-size: 14px;
}
.calc-grid {
display: grid;
grid-template-columns: 1fr 320px;
gap: 18px;
align-items: start;
}
@media (max-width:800px) {
.calc-grid {
grid-template-columns: 1fr;
}
}
.controls {
display: flex;
flex-direction: column;
gap: 12px;
}
.controls label {
display: flex;
flex-direction: column;
gap: 8px;
font-size: 14px;
color: var(--muted);
}
.controls input[type="number"] {
padding: 10px 12px;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.04);
background: transparent;
color: inherit;
outline: none;
}
.controls input:focus {
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.08);
border-color: rgba(99, 102, 241, 0.6);
}
.tip-buttons .buttons {
display: flex;
gap: 8px;
flex-wrap: wrap;
align-items: center;
}
.tipBtn {
padding: 10px 12px;
border-radius: 8px;
border: 0;
background: linear-gradient(90deg, var(--accent), #22c1c3);
color: white;
font-weight: 600;
cursor: pointer
}
.tipBtn.inactive {
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.06);
color: var(--muted)
}
.tip-buttons input {
padding: 8px 10px;
min-width: 80px;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.04);
background: transparent;
color: inherit;
}
.form-actions {
display: flex;
gap: 8px;
margin-top: 6px;
}
.btn {
padding: 10px 14px;
border-radius: 10px;
border: 0;
background: linear-gradient(90deg, var(--accent), #22c1c3);
color: white;
font-weight: 600;
cursor: pointer
}
.btn.secondary {
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.06);
color: var(--muted)
}
.results {
background: rgba(255, 255, 255, 0.02);
padding: 16px;
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.03);
display: flex;
flex-direction: column;
gap: 12px;
}
.result-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.label {
color: var(--muted);
font-size: 14px;
}
.value {
font-family: ui-monospace, monospace;
font-size: 20px;
font-weight: 700;
}
.muted {
font-size: 12px;
color: var(--muted)
}
.error {
color: var(--danger);
font-size: 13px;
min-height: 18px
}
.small {
font-size: 13px;
color: var(--muted)
} Javascript Code
The JavaScript code handles the main functionality of the Tip Calculator. First, it selects all the required HTML elements, including the bill input, number of people input, tip buttons, custom tip field, result areas, error message, and Reset button. The formatCurrency() function formats calculated values as Indian rupee amounts with two decimal places. The calculate() function reads the bill amount, number of people, and selected tip percentage. It also checks whether the entered bill amount and number of people are valid before performing the calculation.
The code calculates the total tip, tip amount per person, and total amount each person needs to pay. These values are then displayed dynamically on the page. Users can select a predefined tip percentage or enter a custom percentage. Event listeners update the calculation whenever users change an input or select a tip option. Finally, the Reset button clears all entered values and restores the calculator to its default state.
// Tip Calculator logic
// Elements
const billInput = document.getElementById('bill');
const peopleInput = document.getElementById('people');
const tipButtons = Array.from(document.querySelectorAll('.tipBtn'));
const customTipInput = document.getElementById('customTip');
const tipPerPersonEl = document.getElementById('tipPerPerson');
const totalPerPersonEl = document.getElementById('totalPerPerson');
const errorEl = document.getElementById('error');
const resetBtn = document.getElementById('resetBtn');
let selectedTip = null; // percentage as number (e.g., 15 for 15%)
// Helpers
function formatCurrency(value) {
// Use simple rupee symbol and 2 decimals. Replace with Intl if desired.
return '₹' + Number(value).toFixed(2);
}
function clearTipSelection() {
selectedTip = null;
tipButtons.forEach(b => b.classList.remove('inactive'));
customTipInput.value = '';
}
// Update calculations
function calculate() {
errorEl.textContent = '';
const bill = parseFloat(billInput.value);
const people = parseInt(peopleInput.value, 10);
// Determine tip percentage
let tipPct = selectedTip;
const customVal = parseFloat(customTipInput.value);
if (!isNaN(customVal) && customVal >= 0) tipPct = customVal;
// Validate inputs
if (isNaN(bill) || bill < 0) {
tipPerPersonEl.textContent = formatCurrency(0);
totalPerPersonEl.textContent = formatCurrency(0);
errorEl.textContent = 'Enter a valid bill amount.';
return;
}
if (isNaN(people) || people <= 0) {
tipPerPersonEl.textContent = formatCurrency(0);
totalPerPersonEl.textContent = formatCurrency(0);
errorEl.textContent = 'Number of people must be at least 1.';
return;
}
if (tipPct === null || isNaN(tipPct) || tipPct < 0) {
// treat no tip as 0%
tipPct = 0;
}
// Math:
// total tip = bill * (tipPct/100)
// tip per person = total tip / people
// total per person = (bill / people) + tip per person
const totalTip = bill * (tipPct / 100);
const tipPerPerson = totalTip / people;
const totalPerPerson = (bill / people) + tipPerPerson;
tipPerPersonEl.textContent = formatCurrency(tipPerPerson);
totalPerPersonEl.textContent = formatCurrency(totalPerPerson);
errorEl.textContent = '';
}
// Tip button clicks
tipButtons.forEach(btn => {
btn.addEventListener('click', (e) => {
// toggle button as selected/inactive
const pct = Number(btn.dataset.tip);
if (selectedTip === pct) {
// deselect
selectedTip = null;
btn.classList.remove('inactive');
} else {
selectedTip = pct;
tipButtons.forEach(b => b.classList.remove('inactive'));
btn.classList.add('inactive'); // visually mark selected (uses same class for styling)
// clear custom input
customTipInput.value = '';
}
calculate();
});
});
// custom tip input
customTipInput.addEventListener('input', () => {
// clear selected quick buttons when user types custom
selectedTip = null;
tipButtons.forEach(b => b.classList.remove('inactive'));
calculate();
});
// inputs update
[billInput, peopleInput].forEach(inp => inp.addEventListener('input', calculate));
// Reset
resetBtn.addEventListener('click', () => {
billInput.value = '';
peopleInput.value = '';
customTipInput.value = '';
clearTipSelection();
tipPerPersonEl.textContent = formatCurrency(0);
totalPerPersonEl.textContent = formatCurrency(0);
errorEl.textContent = '';
});
// initialize defaults
(function init(){
billInput.value = '';
peopleInput.value = '1';
clearTipSelection();
tipPerPersonEl.textContent = formatCurrency(0);
totalPerPersonEl.textContent = formatCurrency(0);
})();
Related Projects
Day 4 : Stop-Watch App
A simple stopwatch with start, stop, and reset buttons.
Concepts: setInterval(), clearInterval(), time logic.
Day 8 : Movie Search App
Search movies and display results with posters using an API.
Concepts: API integration, async/await.
Day 9 : Flashcard Learning App
Create and flip flashcards to study and test your knowledge.
Concepts: DOM manipulation, CSS 3D effects, LocalStorage.