Overview & What You Will Learn

What We Are Building

In this project, we are building a fully interactive digital calculator from scratch using core front-end web technologies (HTML, CSS, and JavaScript). The calculator performs standard mathematical operations including addition, subtraction, multiplication, division, percentage calculations, clear screen (AC), and backspace deletion.

How We Are Building It

We start by structuring the calculator interface with semantic HTML5 elements using custom data-* attributes for buttons. We then style the layout into a clean 4x4 matrix using CSS Grid, CSS custom properties (variables), and Neo-Brutalist shadow borders. Finally, we attach JavaScript event listeners to capture button clicks, track active state, handle mathematical expressions, and render live output updates on the screen.

Key Skills & Concepts You Will Learn:

  • Structuring UI components with semantic HTML <button> and <div> tags
  • Creating responsive keypads using 4-column CSS Grid layouts
  • Using CSS custom properties (--variables) and active press feedback states
  • Handling DOM click events and querying elements with data-* attributes
  • Managing application state for operands, operators, and mathematical evaluation

Interactive Live Demo

HTML, CSS & JS Calculator Preview

Step-by-Step Tutorial

Step 1HTML Structure: Display Screen & History Indicator

We begin by defining the calculator wrapper using a <div> element. Inside, we create a display screen containing two child elements: one for the previous operation history and one for the current number input.

<div class="calculator">
  <div class="display">
    <div id="previous-op" class="previous-op"></div>
    <div id="current-op" class="current-op">0</div>
  </div>
  <!-- Keypad buttons added in Step 2 -->
</div>
💡 Key Concepts & Tips:
  • The #current-op element displays active typing while #previous-op tracks pending calculations.
Step 2HTML Keypad: Action & Numeric Data Buttons

Next, we build a 4x4 matrix of calculator keys using semantic <button> elements. We attach custom data-* attributes (such as data-number and data-action) to cleanly distinguish numeric digits from mathematical operator keys.

<div class="buttons">
  <button class="btn btn-action" data-action="clear">AC</button>
  <button class="btn btn-action" data-action="delete">DEL</button>
  <button class="btn btn-operator" data-action="operator">%</button>
  <button class="btn btn-operator" data-action="operator">÷</button>
  
  <button class="btn" data-number="7">7</button>
  <button class="btn" data-number="8">8</button>
  <button class="btn" data-number="9">9</button>
  <button class="btn btn-operator" data-action="operator">×</button>
  
  <button class="btn" data-number="4">4</button>
  <button class="btn" data-number="5">5</button>
  <button class="btn" data-number="6">6</button>
  <button class="btn btn-operator" data-action="operator">-</button>
  
  <button class="btn" data-number="1">1</button>
  <button class="btn" data-number="2">2</button>
  <button class="btn" data-number="3">3</button>
  <button class="btn btn-operator" data-action="operator">+</button>
  
  <button class="btn" data-number="0">0</button>
  <button class="btn" data-number=".">.</button>
  <button class="btn btn-equals" data-action="equals">=</button>
</div>
💡 Key Concepts & Tips:
  • Using data-* attributes allows JavaScript to query buttons cleanly without clogging class names.
Step 3CSS Grid Layout & Container Spacing

To arrange the calculator keys into an aligned matrix, we use CSS Grid Layout with grid-template-columns: repeat(4, 1fr) and the CSS gap property. We configure color tokens using CSS Custom Properties (--variables) and apply a distinct shadow border using CSS box-shadow.

:root {
  --bg-calc: #1e1e2e;
  --bg-display: #181825;
  --text-color: #f8f8f2;
}

.calculator {
  width: 100%;
  max-width: 360px;
  margin: 0 auto;
  background-color: var(--bg-calc);
  border: 3px solid #111;
  border-radius: 16px;
  padding: 20px;
  box-shadow: 6px 6px 0px #111;
}

.buttons {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
}
💡 Key Concepts & Tips:
  • Setting max-width: 360px ensures the calculator remains perfectly sized on mobile screens.
Step 4CSS Keypad Styling & Double-Span Equals Button

We style the display screen and key buttons for hover and press feedback. To make the equals (=) button span across two grid columns, we use grid-column: span 2 along with a vibrant green highlight color.

.display {
  background-color: var(--bg-display);
  padding: 16px;
  border-radius: 10px;
  text-align: right;
  margin-bottom: 20px;
  min-height: 80px;
}

.btn {
  padding: 14px;
  font-size: 1.2rem;
  font-weight: bold;
  border-radius: 8px;
  cursor: pointer;
  transition: transform 0.1s ease;
}

.btn-equals {
  grid-column: span 2;
  background-color: #2ecc71;
}
💡 Key Concepts & Tips:
  • Use grid-column: span 2 to extend any grid item across multiple grid tracks.
Step 5JavaScript State Tracking & Number Input Appending

In vanilla JavaScript, we store state for currentOperand, previousOperand, and operation. When numeric buttons are clicked, we append digits to the current display string using DOM manipulation.

let currentOperand = '0';
let previousOperand = '';
let operation = null;

const currentDisplay = document.getElementById('current-op');
const previousDisplay = document.getElementById('previous-op');

function appendNumber(number) {
  if (number === '.' && currentOperand.includes('.')) return;
  if (currentOperand === '0' && number !== '.') {
    currentOperand = number;
  } else {
    currentOperand += number;
  }
  updateDisplay();
}
💡 Key Concepts & Tips:
  • Check for decimal points to prevent entering multiple decimals in a single number (e.g. 12.3.4).
Step 6JavaScript Arithmetic Evaluation & Screen Clear

Finally, we implement the compute() function to evaluate math operations (`+`, `-`, `×`, `÷`, `%`), handle clear (`AC`), and delete (`DEL`) actions dynamically.

function compute() {
  let computation;
  const prev = parseFloat(previousOperand);
  const current = parseFloat(currentOperand);
  if (isNaN(prev) || isNaN(current)) return;

  switch (operation) {
    case '+': computation = prev + current; break;
    case '-': computation = prev - current; break;
    case '×': computation = prev * current; break;
    case '÷': computation = current === 0 ? 'Error' : prev / current; break;
    case '%': computation = prev % current; break;
  }

  currentOperand = computation.toString();
  operation = undefined;
  previousOperand = '';
  updateDisplay();
}
💡 Key Concepts & Tips:
  • Always validate inputs with isNaN() before running mathematical operations.
  • Gracefully handle division by zero (prev / 0) to prevent screen errors.

Complete Project Source Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<div class="calculator">
  <div class="display">
    <div id="previous-op" class="previous-op"></div>
    <div id="current-op" class="current-op">0</div>
  </div>
  <div class="buttons">
    <button class="btn btn-action" data-action="clear">AC</button>
    <button class="btn btn-action" data-action="delete">DEL</button>
    <button class="btn btn-operator" data-action="operator">%</button>
    <button class="btn btn-operator" data-action="operator">÷</button>
    
    <button class="btn" data-number="7">7</button>
    <button class="btn" data-number="8">8</button>
    <button class="btn" data-number="9">9</button>
    <button class="btn btn-operator" data-action="operator">×</button>
    
    <button class="btn" data-number="4">4</button>
    <button class="btn" data-number="5">5</button>
    <button class="btn" data-number="6">6</button>
    <button class="btn btn-operator" data-action="operator">-</button>
    
    <button class="btn" data-number="1">1</button>
    <button class="btn" data-number="2">2</button>
    <button class="btn" data-number="3">3</button>
    <button class="btn btn-operator" data-action="operator">+</button>
    
    <button class="btn" data-number="0">0</button>
    <button class="btn" data-number=".">.</button>
    <button class="btn btn-equals" data-action="equals">=</button>
  </div>
</div>
File: index.html (31 lines)HTML

Explore Other Web Projects