Project: Calculator

In the previous lesson, we learned how throttling limits how often a function runs. Now let’s build our first project: a working calculator that brings together everything you know about the DOM, events, and strings.

🎯 What We’ll Build

We will build a calculator that runs in the browser. It has a display at the top and a grid of buttons below it: the digits 0 through 9, the four operators +, -, *, and /, an equals button =, and a clear button C.

When the user clicks a button, the calculator adds that character to the display. When the user clicks =, the calculator evaluates the expression and shows the answer. The C button clears everything and starts over.

This project ties together several JavaScript concepts you have already learned:

  • The DOM to find the display and the buttons on the page.
  • Event listeners with addEventListener to react to clicks.
  • Strings to build the expression one character at a time.
  • Data attributes to tell which button was pressed.

🧱 The HTML

The HTML gives us a div for the display and a button for every key. Each button stores its value in a data-value attribute so the JavaScript can read it later. Here is the markup:

index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Calculator</title>
</head>
<body>
<div class="calculator">
<div class="display" id="display">0</div>
<div class="buttons">
<button data-value="C" class="clear">C</button>
<button data-value="/">/</button>
<button data-value="*">*</button>
<button data-value="-">-</button>
<button data-value="7">7</button>
<button data-value="8">8</button>
<button data-value="9">9</button>
<button data-value="+">+</button>
<button data-value="4">4</button>
<button data-value="5">5</button>
<button data-value="6">6</button>
<button data-value="1">1</button>
<button data-value="2">2</button>
<button data-value="3">3</button>
<button data-value="0">0</button>
<button data-value="=" class="equals">=</button>
</div>
</div>
<script src="calculator.js"></script>
</body>
</html>

Let’s walk through the key parts of this markup:

  • <div class="display" id="display">0</div> is the screen at the top. The id="display" lets us grab it quickly from JavaScript, and the 0 is what shows before the user types anything.
  • <div class="buttons"> wraps every key in one container so we can lay them out as a grid.
  • data-value on each button holds the exact character that button represents. We read this one attribute instead of checking the button’s text, which keeps the logic simple.
  • data-value="C" is the clear key and data-value="=" is the equals key. We give these a class (clear and equals) so they can be styled differently from the digits.
  • <script src="calculator.js"></script> sits at the end of the body so the buttons exist on the page before our JavaScript runs.

⚙️ The JavaScript

The JavaScript listens for clicks, builds the expression as a string, and evaluates it when the user presses =. Here is the full logic:

calculator.js
const display = document.getElementById("display");
const buttons = document.querySelectorAll("button");
let expression = "";
buttons.forEach((button) => {
button.addEventListener("click", () => {
const value = button.dataset.value;
if (value === "C") {
// Clear everything and start over
expression = "";
display.textContent = "0";
return;
}
if (value === "=") {
// Work out the answer
const result = calculate(expression);
display.textContent = result;
expression = String(result);
return;
}
// Any digit or operator: add it to the expression
expression += value;
display.textContent = expression;
});
});
function calculate(text) {
try {
const answer = Function(`"use strict"; return (${text})`)();
if (!isFinite(answer)) {
return "Error";
}
return answer;
} catch {
return "Error";
}
}

Here is how it works, line by line:

  • const display = ... and const buttons = ... grab the display with getElementById and collect every button with querySelectorAll.
  • let expression = ""; is a string that holds what the user has typed so far. It starts empty.
  • buttons.forEach((button) => { ... }) loops over the buttons and attaches a click listener to each one.
  • const value = button.dataset.value; reads the data-value attribute, so we always know exactly which key was pressed.
  • if (value === "C") resets the expression to an empty string and puts 0 back on the display.
  • if (value === "=") calls calculate to evaluate the expression, shows the result, and stores it so the user can keep calculating from the answer.
  • expression += value; handles everything else, a digit or an operator: we add the character to expression and update the display.
  • function calculate(text) turns the expression text into a number. It uses the Function constructor to evaluate the math, wraps the work in a try...catch so a broken expression like 5++ returns "Error" instead of crashing, and checks isFinite so dividing by zero also shows "Error".

A note about evaluating math

This project uses the Function constructor to evaluate the expression, which is simple but can run any code passed to it. That is fine here because the only input comes from our own buttons. In a real app that accepts text from users, parse and compute the math yourself instead of evaluating strings, so you never run untrusted code.

🚀 Try It Yourself!

Get the basic calculator working first, then pick an enhancement to add.

  1. Save the HTML as index.html and the JavaScript as calculator.js in the same folder, then open the page in your browser.
  2. Add keyboard support by listening for keydown on the document. Map number and operator keys to the same logic, Enter to =, and Escape to C.
  3. Add a decimal point button with data-value="." so users can type numbers like 3.14.
  4. Add a percentage button that divides the current number by 100 when clicked.

Reuse your logic

When you add keyboard support, call the same code that the click listener already runs. Move the shared work into one function so the keyboard and the buttons stay in sync.

🧩 What You’ve Learned

  • ✅ How to attach a click listener to many buttons with forEach and addEventListener
  • ✅ How to read a button’s data-value attribute with dataset
  • ✅ How to build an expression string and update the display as the user types
  • ✅ How to evaluate the expression safely with try...catch and isFinite
  • ✅ How a clear button resets the calculator to its starting state

🚀 What’s Next?

You have built your first interactive app. Next we will fetch real data from the internet and display it. Let’s build a Weather App.

Share & Connect