Build Interactive Calculator (JavaScript Project)
JavaScript DOM Manipulation
Day 4: Build an Interactive Calculator – Make Your Webpage Come Alive
Welcome to Day 4
In Days 1–3, you learned variables, functions, and control flow — JavaScript "thinking" behind the scenes. Today you connect that thinking to the actual webpage the user sees. This is called DOM Manipulation, and it's what makes websites truly interactive.
By the end of today, you'll have built a fully working calculator in pure JavaScript — no page reloads, no frameworks, just HTML, CSS, and JS working together.
What You'll Build Today
Understand the "Document Object Model" — how JavaScript sees your HTML page
Use
document.querySelector() to grab buttons, inputs, and divs
Detect button clicks and user interactions with
addEventListener()
Get input values and display results without refreshing
Put it all together in one real, working project
What is the DOM?
When a browser loads your HTML page, it doesn't just display it — it also builds a tree-like map of every element on the page. This map is called the DOM (Document Object Model).
Think of it this way: your HTML file is like a blueprint. The DOM is the actual building that gets constructed from that blueprint. JavaScript can then walk through that building, open doors (read content), paint walls (change styles), or even knock walls down (remove elements).
Your HTML file:
Hello
Welcome!
How the DOM sees it (as a tree):
id="title"
class="description"
JavaScript can grab any of these nodes by their tag, id, or class — then read or change them.
The document Object
In JavaScript, document is your entry point into the DOM. It represents the entire webpage and has built-in methods to find elements.
// The document object represents the whole page
console.log(document); // the entire page
console.log(document.title); // the page title
console.log(document.body); // the element
document.querySelector() — Selecting Elements
document.querySelector() is how you tell "Go find this specific element on the page and give it to me."
It uses the same selectors as CSS — so if you know how to target elements with CSS, you already know how to use querySelector.
Selecting by ID (most common — use #)
// HTML: Hello World
let titleElement = document.querySelector('#title');
// Now titleElement IS the element
// You can read its content:
console.log(titleElement.textContent); // "Hello World"
Selecting by Class (use .)
// HTML: Welcome!
let desc = document.querySelector('.description');
console.log(desc.textContent); // "Welcome!"
Selecting by Tag Name
// Selects the FIRST
Visual: querySelector in Action
HTML (what the user sees):
JavaScript (selecting those elements):
let addButton = document.querySelector('#addBtn');
let resultDiv = document.querySelector('#result');
Points to the input box — you can read what the user typed
Points to the button — you can listen for clicks
Points to the result area — you can write output here
querySelectorAll — Selecting Multiple Elements
When you need all matching elements (not just the first), use querySelectorAll(). It returns a list.
// Select ALL buttons on the page
let allButtons = document.querySelectorAll('button');
// Loop through them
allButtons.forEach(function(btn) {
console.log(btn.textContent);
});
// Prints: "Add", "Subtract", "Multiply", "Divide"
'#myId' → selects element with id="myId"'.myClass' → selects element with class="myClass"'button' → selects a element
Event Listeners — Responding to User Actions
An event is anything that happens on a webpage — a click, a keypress, a mouse hover, a form submission. An event listener is code that waits and watches for a specific event, then runs a function when it happens.
The Syntax:
element.addEventListener('eventType', function() {
// code to run when the event happens
});
The HTML element to watch (e.g., a button)
The event to listen for
Code to run when it happens
Click Events
Simple button click:
// HTML:
let greetBtn = document.querySelector('#greetBtn');
greetBtn.addEventListener('click', function() {
console.log("Button was clicked!");
alert("Hello, World!");
});
What happens step by step:
Common Event Types
// 'click' — user clicks an element
button.addEventListener('click', function() { ... });
// 'input' — user types into an input field
inputField.addEventListener('input', function() { ... });
// 'mouseover' — mouse hovers over element
div.addEventListener('mouseover', function() { ... });
// 'keydown' — user presses any key
document.addEventListener('keydown', function(event) {
console.log("Key pressed:", event.key);
});
Getting Input Values
When users type into an input field, you retrieve what they typed using the .value property.
// HTML:
let nameInput = document.querySelector('#nameInput');
// User typed "Alice" into the input
let typedValue = nameInput.value;
console.log(typedValue); // "Alice"
⚠️ Critical: Input Values Are Always Strings!
This is one of the most common beginner mistakes. Even when a user types a number like 42 into an input, JavaScript sees it as the text "42", not the number 42. You must convert it!
❌ The Problem (without conversion):
// User typed 10 and 5 in two input fields
let num1 = document.querySelector('#num1').value; // "10" (string!)
let num2 = document.querySelector('#num2').value; // "5" (string!)
let result = num1 + num2;
console.log(result); // "105" ← WRONG! It joined the strings!
✅ The Fix (with Number() conversion):
// Convert strings to actual numbers using Number()
let num1 = Number(document.querySelector('#num1').value); // 10 ✓
let num2 = Number(document.querySelector('#num2').value); // 5 ✓
let result = num1 + num2;
console.log(result); // 15 ← Correct!
Visual: String vs Number
String "10" + String "5"
Concatenation (gluing text)
Number(10) + Number(5)
Addition (math)
Number("42") → 42 ← Most clear and recommendedparseInt("42") → 42 ← For whole numbers onlyparseFloat("42.5") → 42.5 ← For decimals
Updating the DOM — Displaying Results
Once you have a result, you need to show it on the page. The main properties for updating elements are textContent and innerHTML.
textContent — Change plain text:
// HTML: Waiting...
let resultDiv = document.querySelector('#result');
resultDiv.textContent = "The answer is 42!";
// The div now shows: The answer is 42!
innerHTML — Change content including HTML tags:
// You can insert HTML tags too
resultDiv.innerHTML = "Result: 42";
// Shows: Result: 42 (with "Result:" in bold)
Changing styles:
// Change CSS styles with JavaScript
resultDiv.style.color = "green";
resultDiv.style.fontWeight = "bold";
resultDiv.style.backgroundColor = "#d4edda";
Visual: Read Input → Process → Update Page
User types "10"
.value
Number("10") = 10
Number()
10 + 5 = 15
arithmetic
Shows "15" on page
.textContent
🛠 Project: Build an Interactive Calculator
Now we apply everything. We'll build a calculator with two number inputs, four operation buttons, and a result display — all updating live without any page reload.
✓ Two input fields for numbers
✓ Four buttons: Add, Subtract, Multiply, Divide
✓ Result displays on the page (no alert, no refresh)
✓ Error handling for division by zero
✓ Error handling for invalid (empty/non-number) inputs
Step 1: The Logic Flow (Before Any Code)
Calculator Logic Flow
Step 2: The HTML Structure (index.html)
JavaScript Calculator
JavaScript Calculator
Enter two numbers and choose an operation
#num1, #num2, #addBtn, #subtractBtn, #multiplyBtn, #divideBtn, and #result.
Step 3: The CSS (style.css)
/* style.css */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
background: #f0f4f8;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.calculator {
background: white;
padding: 30px;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
max-width: 400px;
width: 100%;
text-align: center;
}
h1 {
font-size: 1.5em;
color: #2c3e50;
margin-bottom: 20px;
}
.inputs {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
input[type="number"] {
flex: 1;
padding: 12px;
font-size: 1.1em;
border: 2px solid #ddd;
border-radius: 8px;
text-align: center;
outline: none;
transition: border-color 0.2s;
}
input[type="number"]:focus {
border-color: #3498db;
}
.buttons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 20px;
}
button {
padding: 12px;
font-size: 1em;
font-weight: bold;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background 0.2s, transform 0.1s;
}
button:active {
transform: scale(0.97);
}
#addBtn { background: #2ecc71; color: white; }
#subtractBtn { background: #e74c3c; color: white; }
#multiplyBtn { background: #3498db; color: white; }
#divideBtn { background: #9b59b6; color: white; }
#addBtn:hover { background: #27ae60; }
#subtractBtn:hover { background: #c0392b; }
#multiplyBtn:hover { background: #2980b9; }
#divideBtn:hover { background: #8e44ad; }
#result {
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
font-size: 1.2em;
color: #555;
min-height: 60px;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid #eee;
transition: all 0.3s;
}
#result.success {
background: #d4edda;
border-color: #2ecc71;
color: #1a6b38;
font-weight: bold;
}
#result.error {
background: #f8d7da;
border-color: #e74c3c;
color: #721c24;
}
Step 4: The JavaScript — Building It Step by Step
We'll build script.js in stages, explaining each part before writing it.
Part A: Select All Elements
First, we grab every element we'll need using querySelector. Do this once at the top of your file.
// ===================================
// Part A: Select Elements from the DOM
// ===================================
// Input fields - we'll read .value from these
const num1Input = document.querySelector('#num1');
const num2Input = document.querySelector('#num2');
// Buttons - we'll add click listeners to these
const addBtn = document.querySelector('#addBtn');
const subtractBtn = document.querySelector('#subtractBtn');
const multiplyBtn = document.querySelector('#multiplyBtn');
const divideBtn = document.querySelector('#divideBtn');
// Result display - we'll write .textContent to this
const resultDiv = document.querySelector('#result');
Part B: Write a Helper Function
We'll write a reusable function to get both numbers and check if they're valid. This avoids repeating the same code four times.
// ===================================
// Part B: Helper Functions
// ===================================
// This function shows a result on the page
function showResult(message, isError) {
resultDiv.textContent = message;
// Change styling based on success or error
if (isError) {
resultDiv.className = 'error'; // red styling
} else {
resultDiv.className = 'success'; // green styling
}
}
// This function gets the numbers from inputs
// Returns the numbers, or null if inputs are invalid
function getNumbers() {
let num1 = Number(num1Input.value);
let num2 = Number(num2Input.value);
// Check if inputs are empty
if (num1Input.value === '' || num2Input.value === '') {
showResult("⚠️ Please fill in both number fields!", true);
return null; // Stop — invalid input
}
// Check if inputs are actual numbers (NaN = Not a Number)
if (isNaN(num1) || isNaN(num2)) {
showResult("⚠️ Please enter valid numbers!", true);
return null; // Stop — invalid input
}
// All good! Return the numbers as an object
return { num1, num2 };
}
isNaN() stands for "is Not a Number." It returns true if something is not a valid number.isNaN(42) → false (42 IS a number)isNaN("hello") → true ("hello" is NOT a number)
Part C: Add Event Listeners for Each Button
// ===================================
// Part C: Button Event Listeners
// ===================================
// --- ADD BUTTON ---
addBtn.addEventListener('click', function() {
let numbers = getNumbers();
if (numbers === null) return; // Stop if inputs invalid
let result = numbers.num1 + numbers.num2;
showResult(`${numbers.num1} + ${numbers.num2} = ${result}`, false);
});
// --- SUBTRACT BUTTON ---
subtractBtn.addEventListener('click', function() {
let numbers = getNumbers();
if (numbers === null) return;
let result = numbers.num1 - numbers.num2;
showResult(`${numbers.num1} - ${numbers.num2} = ${result}`, false);
});
// --- MULTIPLY BUTTON ---
multiplyBtn.addEventListener('click', function() {
let numbers = getNumbers();
if (numbers === null) return;
let result = numbers.num1 * numbers.num2;
showResult(`${numbers.num1} × ${numbers.num2} = ${result}`, false);
});
// --- DIVIDE BUTTON ---
divideBtn.addEventListener('click', function() {
let numbers = getNumbers();
if (numbers === null) return;
// Special check: can't divide by zero!
if (numbers.num2 === 0) {
showResult("⚠️ Cannot divide by zero!", true);
return;
}
let result = numbers.num1 / numbers.num2;
// Round to 4 decimal places to keep it clean
let roundedResult = Math.round(result * 10000) / 10000;
showResult(`${numbers.num1} ÷ ${numbers.num2} = ${roundedResult}`, false);
});
The Complete script.js File
Here is the complete, ready-to-use JavaScript file. Every part explained above combined:
// ============================================
// JavaScript Day 4: Interactive Calculator
// ============================================
// PART A: Select DOM Elements
// ============================================
const num1Input = document.querySelector('#num1');
const num2Input = document.querySelector('#num2');
const addBtn = document.querySelector('#addBtn');
const subtractBtn = document.querySelector('#subtractBtn');
const multiplyBtn = document.querySelector('#multiplyBtn');
const divideBtn = document.querySelector('#divideBtn');
const resultDiv = document.querySelector('#result');
// PART B: Helper Functions
// ============================================
// Display result with correct styling
function showResult(message, isError) {
resultDiv.textContent = message;
resultDiv.className = isError ? 'error' : 'success';
}
// Get and validate the two input numbers
function getNumbers() {
if (num1Input.value === '' || num2Input.value === '') {
showResult("⚠️ Please fill in both number fields!", true);
return null;
}
let num1 = Number(num1Input.value);
let num2 = Number(num2Input.value);
if (isNaN(num1) || isNaN(num2)) {
showResult("⚠️ Please enter valid numbers!", true);
return null;
}
return { num1, num2 };
}
// PART C: Event Listeners
// ============================================
addBtn.addEventListener('click', function() {
let numbers = getNumbers();
if (numbers === null) return;
let result = numbers.num1 + numbers.num2;
showResult(`${numbers.num1} + ${numbers.num2} = ${result}`, false);
});
subtractBtn.addEventListener('click', function() {
let numbers = getNumbers();
if (numbers === null) return;
let result = numbers.num1 - numbers.num2;
showResult(`${numbers.num1} - ${numbers.num2} = ${result}`, false);
});
multiplyBtn.addEventListener('click', function() {
let numbers = getNumbers();
if (numbers === null) return;
let result = numbers.num1 * numbers.num2;
showResult(`${numbers.num1} × ${numbers.num2} = ${result}`, false);
});
divideBtn.addEventListener('click', function() {
let numbers = getNumbers();
if (numbers === null) return;
if (numbers.num2 === 0) {
showResult("⚠️ Cannot divide by zero!", true);
return;
}
let result = Math.round((numbers.num1 / numbers.num2) * 10000) / 10000;
showResult(`${numbers.num1} ÷ ${numbers.num2} = ${result}`, false);
});
Step 5: Test Every Scenario
Enter 10 and 5, click Add → Should show "10 + 5 = 15"
Enter 10 and 3, click Divide → Should show "10 ÷ 3 = 3.3333"
Enter 5 and 0, click Divide → Should show error "Cannot divide by zero!"
Leave fields empty, click any button → Should show "Please fill in both fields"
Enter -5 and 3, click Multiply → Should show "-5 × 3 = -15"
🔍 Interactive Demo — Try It Now
Here's the calculator running live right in this lesson. Try it yourself!
🧮 Interactive Calculator Demo
Exercises: Extend Your Calculator
Once your calculator works, challenge yourself with these extensions to reinforce your understanding.
Exercise 1: Add a Clear Button
Task: Add a "Clear" button that empties both inputs and resets the result message.
HTML to add (inside .buttons div):
JavaScript to add:
const clearBtn = document.querySelector('#clearBtn');
clearBtn.addEventListener('click', function() {
num1Input.value = ''; // Empty first input
num2Input.value = ''; // Empty second input
resultDiv.textContent = 'Enter two numbers and choose an operation';
resultDiv.className = ''; // Remove success/error styling
});
Exercise 2: Add a Power Button (Bonus)
Task: Add a "Power" button that raises the first number to the power of the second (e.g., 2^8 = 256).
Hint:
// JavaScript has a built-in power operator
let result = Math.pow(2, 8); // 256
// Or use ** operator:
let result2 = 2 ** 8; // 256 (same thing)
Exercise 3: Show Calculation History
Task: Keep a list of the last 5 calculations and display them below the result.
Starter code structure:
// Add to your HTML:
//
let history = []; // An array to store past calculations
const historyDiv = document.querySelector('#history');
function addToHistory(calculation) {
history.unshift(calculation); // Add to front of array
if (history.length > 5) history.pop(); // Keep only last 5
// Display history
historyDiv.innerHTML = 'History:
' +
history.join('
');
}
// Then in each button listener, call:
// addToHistory(`${num1} + ${num2} = ${result}`);
File Structure Summary
📁 calculator-project/
├── 📄 index.html ← The structure (inputs, buttons, result div)
├── 🎨 style.css ← The styling (layout, colors, transitions)
└── ⚡ script.js ← The logic (querySelector, addEventListener, values)
Testing Your Calculator Checklist
calculator-project/
index.html and paste the HTML code
style.css and paste the CSS code
script.js and paste the JavaScript code
index.html in your browser
Key Concepts Quick Reference
// SELECT an element
let el = document.querySelector('#myId');
// READ text content
let text = el.textContent;
// WRITE text content
el.textContent = "New text!";
// READ an input value
let val = inputEl.value; // Always a string!
// CONVERT string to number
let num = Number(val);
// LISTEN for a click
el.addEventListener('click', function() {
// runs when clicked
});
// CHANGE a style
el.style.color = 'green';
el.style.backgroundColor = '#d4edda';
Complete this lesson
Mark as complete to track your progress