How to Build a Calculator With Javascript
How to Build a Calculator With JavaScript
Building a calculator is a rite of passage for new programmers. It’s a perfect project for absolute beginners because it combines simple HTML structure, basic CSS styling, and just enough JavaScript logic to feel rewarding without being overwhelming. By the end of this tutorial, you’ll have a working calculator that can add, subtract, multiply, and divide, plus you’ll understand exactly how each piece fits together.
We’ll create a calculator that runs entirely in your browser—no server needed, no complex setup. You’ll learn how to capture button clicks, build a mathematical expression as a string, evaluate it safely, and handle common errors like dividing by zero. Let’s dive in and build something useful while learning fundamental JavaScript concepts along the way.
What You’ll Need
Before we start, make sure you have:
- A text editor (VS Code, Sublime Text, or even Notepad)
- A modern web browser (Chrome, Firefox, Edge, or Safari)
- Basic familiarity with HTML tags and CSS properties
- Curiosity and patience!
Step-by-Step Guide
Step 1: Create the HTML Structure
First, let’s build the skeleton of our calculator. We’ll create a display area to show numbers and a grid of buttons for input. The key insight here is using data-key attributes on our buttons. These custom attributes let us store what each button represents (a number or an operator) separately from what it displays.
Create a new file called calculator.html and add this code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript Calculator</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="calculator">
<input type="text" id="display" readonly />
<div id="keys">
<button data-key="7">7</button>
<button data-key="8">8</button>
<button data-key="9">9</button>
<button data-key="/">÷</button>
<button data-key="4">4</button>
<button data-key="5">5</button>
<button data-key="6">6</button>
<button data-key="*">×</button>
<button data-key="1">1</button>
<button data-key="2">2</button>
<button data-key="3">3</button>
<button data-key="-">−</button>
<button data-key="0">0</button>
<button data-key=".">.</button>
<button data-key="=">=</button>
<button data-key="+">+</button>
<button data-key="C" class="clear">Clear</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
What this code does:
- The
<input id="display">is a read-only text field that shows the current calculation and result. We make it read-only so users can’t type directly, forcing them to use our buttons. - Each
<button>has adata-keyattribute storing its actual value. For example, the ”×” button stores*because that’s what JavaScript understands for multiplication. - The
id="keys"container holds all buttons, which we’ll target with JavaScript. - We link to a CSS file for styling and a JavaScript file for functionality.
Step 2: Add Basic CSS Styling
While not strictly required, styling makes your calculator usable and pleasant to look at. Create a style.css file in the same folder:
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.calculator {
background: #2c3e50;
padding: 20px;
border-radius: 10px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
}
#display {
width: 100%;
height: 60px;
font-size: 2em;
text-align: right;
padding: 10px;
margin-bottom: 15px;
border: none;
border-radius: 5px;
background: #34495e;
color: white;
box-sizing: border-box;
}
#keys {
display: grid;
grid-template-columns: repeat(4, 60px);
gap: 10px;
}
button {
height: 60px;
font-size: 1.2em;
border: none;
border-radius: 5px;
background: #3498db;
color: white;
cursor: pointer;
transition: background 0.2s;
}
button:hover {
background: #2980b9;
}
button.clear {
grid-column: span 4;
background: #e74c3c;
}
button.clear:hover {
background: #c0392b;
}
What this code does:
- Centers the calculator on the page with a modern gradient background
- Creates a dark theme for the calculator body
- Uses CSS Grid to arrange buttons in 4 columns automatically
- Styles the display with large, right-aligned text
- Adds hover effects for better user feedback
- Makes the Clear button span all columns and appear in red
Step 3: Listen for Button Clicks with JavaScript
Now for the magic! Create a script.js file. We’ll use event delegation, a powerful pattern where we listen for clicks on the entire button container rather than each individual button. This is more efficient and easier to maintain.
// Get references to our display and keys container
const display = document.querySelector('#display');
const keys = document.querySelector('#keys');
// Listen for clicks on the entire keys container
keys.addEventListener('click', (event) => {
// event.target is the actual button that was clicked
const key = event.target.getAttribute('data-key');
// If clicked something without data-key (like the gap between buttons), exit
if (!key) return;
// If the equals button was clicked, evaluate the expression
if (key === '=') {
evaluate();
return;
}
// If clear button was clicked, reset the display
if (key === 'C') {
display.value = '';
return;
}
// Otherwise, add the key to the display
display.value += key;
});
What this code does:
document.querySelector()finds elements in our HTML using CSS selectorsaddEventListener('click', ...)runs our function whenever someone clicks inside the keys containerevent.target.getAttribute('data-key')gets the value from the clicked button’sdata-keyattribute- The
if (!key) return;line is a guard clause that exits early if the user clicked on empty space - We build the expression as a string by appending each key to
display.value - Special handling for
=andCbuttons
Step 4: Evaluate the Expression Safely
The final piece is the evaluate() function. Never use eval() in production code—it’s dangerous because it can execute arbitrary code. Instead, we use the Function constructor, which is safer for simple math.
function evaluate() {
try {
// Get the current expression from the display
const expression = display.value;
// Don't evaluate if display is empty
if (!expression) return;
// Check for division by zero
if (expression.includes('/0')) {
display.value = 'Error: Divide by zero';
return;
}
// Create a function that returns the evaluated expression
const result = Function(`'use strict'; return (${expression})`)();
// Show the result, handling very large/small numbers
display.value = Number.isFinite(result) ? result : 'Error';
} catch (error) {
// If anything goes wrong, show an error message
display.value = 'Error';
console.error('Calculation error:', error);
}
}
What this code does:
- Wraps our evaluation in a
try...catchblock to handle errors gracefully - First checks if the expression contains
/0to prevent division by zero Function(\’use strict’; return (${expression})`)()` creates a new function that only returns the result of our math expressionNumber.isFinite()ensures the result is a valid number (not Infinity or NaN)- If anything fails, shows “Error” and logs details to the console for debugging
Common Mistakes to Avoid
-
Using
eval()instead ofFunction(): Theeval()function can execute any JavaScript code, making it a security risk. Malicious input could steal data or crash your page.Function()creates a sandboxed environment that’s much safer for calculations. -
Forgetting to validate input: Beginners often trust user input completely. Always check for division by zero, empty expressions, and invalid characters before evaluating.
-
Not handling the case where nothing is clicked: The
if (!key) return;guard clause is crucial. Without it, clicking the space between buttons would cause errors when trying to getdata-keyfrom non-button elements. -
Typos in selectors: A single wrong character in
document.querySelector('#display')means JavaScript can’t find your element. The#is essential for IDs, and selectors are case-sensitive. -
Forgetting
readonlyon the display: If users can type directly into the display, they might enter invalid characters that break your calculator. Keep it read-only for consistency. -
Missing the
Cbutton logic: Many tutorials forget the clear functionality, forcing users to refresh the page. Always include a way to reset the calculator.
Troubleshooting Tips
Problem: Nothing happens when I click buttons
- Action: Open Developer Tools (F12 or Ctrl+Shift+I / Cmd+Option+I) and check the Console tab. Look for red error messages.
- Action: Add
console.log('Button clicked:', key);inside your event listener to verify clicks are being detected. - Action: Double-check that your
<script src="script.js"></script>tag is at the bottom of the body, just before</body>.
Problem: The display shows “undefined” or “[object Object]”
- Action: This usually means
event.targetisn’t a button. Addconsole.log(event.target);to see what you’re actually clicking. Make sure you’re clicking buttons, not the container div. - Action: Verify every button has a
data-keyattribute. Missing attributes returnnull, which gets converted to the string “null”.
Problem: Calculations give wrong results
- Action: Check your
data-keyvalues. The multiplication button must use*not×, and division must use/not÷. JavaScript only understands ASCII operators. - Action: Use
console.log('Expression:', display.value);right before evaluation to see exactly what’s being calculated.
Problem: Division by zero shows “Infinity” instead of an error
- Action: Ensure your
/0check runs before evaluation. The check must beexpression.includes('/0')notexpression.includes('/0')with spaces around the zero.
Problem: Decimal numbers don’t work correctly
- Action: Check that your decimal button has
data-key="."and that users can’t enter multiple decimals in one number. You might need to add validation to prevent1.2.3.
Problem: Keyboard doesn’t work
- Action: This tutorial focuses on mouse clicks. To add keyboard support, you’d need a separate
keydownevent listener. Try this as a practice exercise!
Practice Exercises to Level Up
-
Add Keyboard Support: Extend your calculator to respond to keyboard input. Listen for
keydownevents and map number keys and operators to your existing functions. Don’t forget Enter for equals and Escape for clear! -
Prevent Invalid Input: Improve the calculator so users can’t enter two operators in a row (like
5++3) or multiple decimal points in one number. You’ll need to add validation logic before appending each key. -
Add Memory Functions: Implement MC (Memory Clear), MR (Memory Recall), M+ (Memory Add), and M- (Memory Subtract) buttons. Store the memory value in a variable and update the display accordingly.
-
Create a Scientific Mode: Add buttons for square root, power, and percentage. You’ll need to enhance the
evaluate()function to handle these operations safely. -
Build a History Feature: Store the last 10 calculations in an array and display them below the calculator. This teaches you about arrays, DOM manipulation, and persisting data.
Next Steps on Your Journey
Now that you have a working calculator, you have a solid foundation in DOM manipulation, event handling, and basic validation. Here are some paths forward:
- Turn it into a portfolio project: Add advanced features like theming, sound effects, or animation. Host it on GitHub Pages to share with potential employers.
- Learn about code organization: As projects grow, keeping all code in one file becomes messy. Research JavaScript modules and how to split your code into separate files for UI, logic, and utilities.
- Explore calculator libraries: For production apps, consider math libraries like
math.jsthat handle complex expressions, units, and edge cases better than our simple evaluator. - Build a different UI: Try making a calculator with a single text input that parses natural language like “five plus three” instead of button clicks. This introduces you to string parsing and regular expressions.
- Add unit tests: Learn about Jest or Vitest and write tests for your
evaluate()function. Testing is a crucial skill for professional developers.
Summary
You just built a fully functional calculator from scratch! You learned how to:
- Structure HTML with semantic elements and data attributes
- Use CSS Grid for clean, responsive layouts
- Implement event delegation for efficient event handling
- Build expressions as strings and evaluate them safely
- Handle errors gracefully with try-catch blocks
- Validate user input to prevent common errors
This project teaches you more than just calculator logic—it introduces patterns you’ll use in countless future projects. The event delegation pattern works for any interactive UI, the validation approach applies to all user input, and the safety-first mindset is essential for writing secure code.
Keep experimenting with the practice exercises, and don’t be afraid to break your calculator and fix it again. That’s how you learn. Happy coding!