Build an Interactive Calculator
20 minBeginnerHTML · CSS · JS
In this lesson
- ▸Keep an app's state in a few variables and update the page from it
- ▸Separate pure logic (
calculate) from DOM code, and handle edge cases like dividing by zero - ▸Connect many buttons with data attributes and add keyboard shortcuts
The big idea
An interactive app is a loop: the user does something → an event handler updates the state → the page is redrawn from the state. Keep those three parts separate and even a calculator stays simple.
This is your capstone for the track so far. The HTML and CSS are ready; you'll write all the behaviour. You'll use functions, conditions, strings, arrays, loops, the DOM and events — everything at once.
1. Plan the state
Before writing code, ask: what does the calculator need to remember? For 12 + 3 = it needs the number being typed, the first number, and the chosen operator. That's the state:
let current = "0"; // what's being typed — a STRING, so "1" then "2" makes "12"
let previous = null; // the first number, saved when you press an operator
let operator = null; // "+", "-", "*" or "/"- Press
1,2→currentbecomes"12". - Press
+→previous = 12,operator = "+",currentresets to"0". - Press
3→currentis"3". - Press
=→calculate(12, "+", 3)gives15, which becomes the newcurrent.
2. Keep the maths separate
calculate(a, op, b) should only do maths: numbers in, answer out. No document, no events. A function like that is easy to test and easy to reuse — the buttons and the keyboard will both call it.
Two edge cases real calculators handle
Dividing by zero: in JavaScript 8 / 0 is Infinity, which isn't a helpful answer — show Error instead.
Floating-point noise: computers store decimals in binary, so 0.1 + 0.2 is 0.30000000000000004. Rounding to about 10 decimal places — Math.round(result * 1e10) / 1e10 — hides it.
3. Wire up many buttons at once
Each digit button carries its value in a data attribute, like data-digit="7". JavaScript reads it as button.dataset.digit. So instead of ten separate listeners, one loop does it:
// <button data-digit="7">7</button>
for (const button of document.querySelectorAll("[data-digit]")) {
button.addEventListener("click", () => inputDigit(button.dataset.digit));
}Build in small steps and press Run often: get one digit showing, then several, then the operator, then =. When something breaks, console.log(current, previous, operator) inside your functions shows you the state.
Write calculate(a, op, b). It returns the answer for +, -, * and /, and the string "Error" when dividing by zero or when op is anything else.
Round the result so calculate(0.1, "+", 0.2) gives exactly 0.3.
Checks
- All four operators work
- Divide by zero and unknown operators give "Error"
- 0.1 + 0.2 gives 0.3
Check understanding
What you learned
- ✓Plan the state first: what must the app remember between clicks?
- ✓Keep pure logic (
calculate) separate from DOM and event code. - ✓Data attributes + one loop connect many similar buttons;
datasetreads them. - ✓Handle edge cases on purpose: division by zero, repeated dots, floating-point noise.
Console output from your code appears here.