## EngEd Community

Section’s Engineering Education (EngEd) Program fosters a community of university students in Computer Science related fields of study to research and share topics that are relevant to engineers in the modern technology landscape. You can find more information and program guidelines in the GitHub repository. If you're currently enrolled in a Computer Science related field of study and are interested in participating in the program, please complete this form .

# How to Build a Calculator using JavaScript

##### May 28, 2021

Building a web calculator is a great project, especially if you have just started learning JavaScript. It is quite simple for people of any skill level. This project covers the interactions with UI and key JavaScript methods.

In this article, you will be taken through the various HTML and CSS elements along with Vanilla JavaScript and modern ES6 practices used in building a functional and responsive calculator, as shown in the image below:

### Prerequisites

• Any good Text editor.
• Basic understanding of JavaScript and HTML.

### Designing the calculator

To get started, you need to consider the basic functionalities of a calculator. They include `addition`, `subtraction`, `multiplication`, `division`, `delete`, `all-clear`, and of course, the ability to use `decimal numbers` in performing these operations.

In your text editor, create `three` separate folders for your `HTML`, `CSS` and `JavaScript`. This just basically makes your code more organized.

In your `HTML` folder, you can link `CSS` and `JavaScript` files using the code below:

``````<!DOCTYPE html>
<html lang="en" dir="ltr">
<meta charset="utf-8">
<title>Calculator</title>
<script src="Calculator with JS\script.js" defer></script>
``````

The next thing you need to do is add all the different HTML elements. We will use `grid` for a nice design. Therefore, create a `div` with a class named `calculator-grid`.

``````   <div class="calculator-grid">
``````

You will put all the different `HTML elements` and `buttons` inside the above `calculator-grid` div.

Below is the HTML code containing the required components:

``````<!DOCTYPE html>
<html lang="en" dir="ltr">

<meta charset="utf-8">
<title>Calculator</title>
<script src="Calculator with JS\script.js" defer></script>
<div class="calculator-grid">
<div class="output">
<div class="previous-operand"></div>
<div class="current-operand"></div>
</div>
<button class="span-two">AC</button>
<button>DEL</button>
<button>÷</button>
<button>1</button>
<button>2</button>
<button>3</button>
<button>*</button>
<button>4</button>
<button>5</button>
<button>6</button>
<button>+</button>
<button>7</button>
<button>8</button>
<button>9</button>
<button>-</button>
<button>.</button>
<button>0</button>
<button class="span-two">=</button>
</div>
<body>
</body>
</html>
``````

The above HTML code contains several `div` classes. The `output` class represents the calculator screen. The `previous-operand` represents the result of the `previous` operation in the calculator, while the `current-operand` class represents the `current` operation on the calculator.

The `span-two` class represents the buttons that will occupy `two` columns on the calculator. You can `copy paste` the division sign (÷) from google or anywhere else since it is not available on your keyboard.

This is how your calculator would look like at this point:

### Styling the calculator

Next, we need to style the calculator using `CSS`. First, select all the elements, including the `before` and `after` elements. We can then apply the `box-sizing` attribute and set it as `border-box`.

You can also change the `font-family` and `font-weight` of the calculator using the code below:

``````*, *::before, *::after {
box-sizing: border-box;
font-family: Gotham Rounded, sans-serif;
font-weight: normal;
}
``````

Next, we need to style the background by using the `body` element, as shown below:

``````body {
margin: 0;
}
``````

The next step is to style the `calculator-grid` div that we defined earlier. It wraps all of our different `buttons` and `elements`. We can set the `display` to `grid`.

We can also use the `justify-content` attribute to set it to the center of the screen. Besides, the `align-content` attribute can help align items to the center of the screen.

At this point, you may notice that the `calculator-grid` is not arranged vertically. We can fix that by setting the `min-height` to `100vh`. This means that the calculator grid will fill `100%` of the height all the time.

Another thing is that `buttons` should be aligned at the center of your screen and spaced out. To make a regular calculator, we have to use `grid-template-columns` then set it to `repeat`, and each column could be `100px wide`. We can also do the same thing for the `grid-template-rows`.

Here is the code below:

``````.calculator-grid {
display: grid;
justify-content: center;
align-items: center;
min-height: 100vh;
grid-template-columns: repeat(4, 100px);
grid-template-rows: minmax(120px, auto) repeat(5, 100px);
}
``````

For the `output screen` to grow as large as it needs to and be adaptable to any number of input values, we need to set the `minmax` value to 120px and the `maximum value` to `auto`, as demonstrated in the code above.

Here is how your calculator looks like at this point:

In order to properly position buttons, we should select all the buttons in the `calculator-grid` and apply these `CSS` elements, as shown below:

``````.calculator-grid > button {
cursor: pointer;
font-size: 2rem;
border: 1px, solid #FFFFFF;
outline: none;
background-color: rbga(255, 255, 255, 0.75);
}

.calculator-grid > button:hover {
background-color: #a9a9a9;
}
``````

At this point, we can improve the calculator’s design by changing the `align-items` attribute to `align-content` and set it to the `center`.

We should then style the `span-two` class, which affects the `All-clear` and `Delete` buttons. We can set the `grid-column` to span `two` columns.

### Styling the Output Window

Another important thing is to style the `output` displayed on the calculator. We can do that by adding a dummy text that says `123 +` to represent your previous operand and `456` to represent the current operand.

Here is how the HTML code will look like:

``````<div class="output">
<div class="previous-operand">123 +</div>
<div class="current-operand">456</div>
``````

This way, you have a little bit of dummy text we can play around with while styling. Now, we can go ahead and style it.

The first thing we can do is to set the `output` to `span` across the entire `width` of the calculator. We can do this by using the `grid-column` attribute again and setting it to span from column `1 to -1`, essentially just the last column.

Next, we will change the `background-color` to `black` with transparency of `75%`. Then, we will align all the elements inside the container.

The easiest way is by using `flex`. Therefore, set the `display` attribute to `flex` and `align-items` attribute to `flex-end`. The output elements will be positioned at the `right` side of the calculator.

To space them out, we can use the `justify-content` attribute and set it to `space-around`. We can also change the `flex-direction` and set it to `column` to align the output elements vertically.

Next, we can set the `padding` to any desired value. Also, to make the output elements `wrap` when they get too long, we can use the `word-wrap` attribute to choose where the words should break.

Besides, we can add a `word-break` and set it to `break-all`. We should style the `previous` and `current` operands in the output class.

The final `CSS` code comes out like this:

``````*, *::before, *::after {
box-sizing: border-box;
font-family: Gotham Rounded, sans-serif;
font-weight: normal;
}

body {
margin: 0;
}

.calculator-grid {
display: grid;
justify-content: center;
align-content: center;
min-height: 100vh;
grid-template-columns: repeat(4, 100px);
grid-template-rows: minmax(120px, auto) repeat(5, 100px);
}

.calculator-grid > button {
cursor: pointer;
font-size: 2rem;
border: 1px, solid #FFFFFF;
outline: none;
background-color: rbga(255, 255, 255, 0.75);
}

.calculator-grid > button:hover {
background-color: #a9a9a9;
}

.span-two {
grid-column: span 2;
background-color: rgba(139, 0, 139, 0.8);
}

.output{
grid-column: 1 / -1;
background-color: rgba(0, 0, 0, 0.75);
display: flex;
align-items: flex-end;
justify-content: space-around;
flex-direction: column;
word-wrap: break-word;
word-break: break-all;
}

.output .previous-operand{
color: rgba(255,255, 255, 0.75);
font-size: 1.5rem;
}

.output .current-operand{
color: white;
font-size: 2.5rem;
}
``````

At this point, the calculator has already taken shape. Now, it is time to make it functional using JavaScript.

### The actual JavaScript

First, we should select all our calculator’s buttons and operations. We can do this by putting some classes in the HTML file. However, since we do not want to mix `CSS` classes with `JavaScript` classes, we can use `data attributes` to select them instead.

`data-operation` to represent your operation buttons, `data-numbers` to represent the `number` buttons, `data-all-clear` to represent the `All-Clear` button and `data-delete` to represent the `Delete` button. We can add these classes to the `previous-operand` and `current-operand`.

Here’s how it would look like in your code:

``````  <div data-previous-operand class="previous-operand"></div>
<div data-current-operand class="current-operand"></div>
<button data-all-clear class="span-two">AC</button>
<button data-delete>DEL</button>
<button data-operation>÷</button>
<button data-number>1</button>
<button data-number>2</button>
<button data-number>3</button>
<button data-operation>*</button>
<button data-number>4</button>
<button data-number>5</button>
<button data-number>6</button>
<button data-operation>+</button>
<button data-number>7</button>
<button data-number>8</button>
<button data-number>9</button>
<button data-operation>-</button>
<button data-number>.</button>
<button data-number>0</button>
<button data-equals class="span-two">=</button>
``````

The additions above are the only changes we need to make to the `HTML` file to select these elements in the JavaScript folder.

In the JavaScript file, define some `constant variables` which will represent the `number` buttons. We will then perform a query using `document.querySelectorAll()`. This function will allow us to get all elements that match a certain string.

In this case, we pick a `data` attribute that must be inside of brackets and we select ‘[data-number]’ which is going to select all `number` elements.

We can do the same thing but for the `operation` buttons. This also goes for the `Equals`, `All-clear` and `Delete` buttons as well as your `previousOperandTextElement` and `currentOperandTextElement`.

The code will come out like this:

``````const numberButtons = document.querySelectorAll('[data-number]')
const operationButtons = document.querySelectorAll('[data-operation]')
const equalsButton = document.querySelector('[data-equals]')
const deleteButton = document.querySelector('[data-delete]')
const allClearButton = document.querySelector('[data-all-clear]')
const previousOperandTextElement = document.querySelector('[data-previous-operand]')
const currentOperandTextElement = document.querySelector('[data-current-operand]')
``````

You may notice that `document.querySelectorAll` was only used for the `numbers` and `operation` buttons. Well, this is because these buttons appear several times on the calculator.

Now that we have everything selected, we can start coding to make the calculator work. The first thing we should consider is how we will store the output.

We can do that by creating a calculator class at the top of the file. In this class, we will put a constructor that will take all the inputs for it and all the calculator functions.

This constructor is going to take the `previousOperandTextElement` and `currentOperandTextElement` so that we can determine where to place the display text for your calculator. We also need to create some variables in this class.

As soon as we create the calculator, we should call the `this.clear` function because we have to reset the inputs.

Here’s how the code will look like:

``````class Calculator {
constructor(previousOperandTextElement, currentOperandTextElement) {
this.previousOperandTextElement = previousOperandTextElement
this.currentOperandTextElement = currentOperandTextElement
this.clear()
}
``````

### The calculator functions

Next, we have to define the different operations that the calculator will perform. The first one is the `clear()` function, which will clear all the different variables. The next method is `delete()` for clearing a `single` number.

We will also create a function that determines what will occur every time a user clicks on a number to add to the display called `appendNumber(number)`.

We need a `chooseOperation(operation)` function that controls what will happen anytime a user clicks on any `operation` button.

Another key function is `compute()`. It takes the values inside your calculator and displays the result.

Finally, a `updateDisplay()` function lets us update the values inside of the output.

These functions are illustrated in the code snippet below:

``````clear() {
}

delete() {
}

appendNumber(number) {
}

chooseOperation(operation) {
}

compute() {
}

updateDisplay() {
}
``````

Now that we have defined all operations, we can now think about the different properties the calculator needs to store. We should determine the `previous operand` the user entered, the `current operand` they are working on, and the `operation` they have selected.

Let’s start working on the functions.

### clear() function

The `clear()` function will delete all the displayed values. We should set `this.currentOperand` to an empty string if the values on the output are removed. We can also do the same for the `previous operand`. We have to change `this.operation` to be `undefined`.

Here’s how the `clear` function should look like:

``````clear() {
this.currentOperand = ''
this.previousOperand = ''
this.operation = undefined
}
``````

Next, let’s focus on hooking all the `variables` and making them operate on the calculator object. The first thing we should do is to create a `calculator constant` and set it to `new calculator` then, we pass everything from the constructor into it. We then pass in the `previous` and `current operand` text elements.

Here is how it looks like in the code:

``````const calculator = new Calculator(previousOperandTextElement, currentOperandTextElement)
``````

### appendNumber(number) function

Now that we have passed those elements in, we can then use this calculator object.

We will select a `number` button, and then use a `for.each` statement to loop over all these different buttons. We can also add an `EventListener` on the buttons using `button.addEventListener`. The `EventListener` will invoke something whenever the button is clicked.

In this case, we will only add a number to the calculator. This can be done by calling the `appendNumber` function and using `button.innerText` to display it.

Once that is done, we need to call the `calculator.updateDisplay` method, thereby making sure that the `displayed values` are constantly updated every time we click on a button on the calculator.

The code snippet is shown below:

``````numberButtons.forEach(button => {
calculator.appendNumber(button.innerText)
calculator.updateDisplay()
})
})
``````

To ensure that everything we have written is working, inside the `updateDisplay()` function, add `this.currentOperandTextElement.innerText = this.currentOperand`.

Inside the `appendNumber()` function, we will also change the `current operand` to match that number instead of `appending` the number.

When we click on a number on the calculator, it should be displayed in the output box. However, you may notice that nothing shows up when you click on `operation` buttons. The appending number functions are, therefore, properly assigned to all the buttons.

Next, let’s write the `appendNumber()` function. All you need to do is to update the `current operand` value and append the number. We can use `this.currentOperand` and convert it to a string if it’s a number. This way, we can easily append something to the end by using “+”.

Note that we should convert numbers to a string to prevent the compiler from performing the actual operation. When you save the file and click on numbers, you find that they constantly get added to the list. But, the period(.) symbol is also added when clicked.

We can prevent this by checking if the string of numbers in the output includes a period(.), then `return`. This will stop your function from executing any further. Now, if you try to add multiple periods, it will only add one.

Below is the complete `appendNumber()`:

``````  appendNumber(number) {
if (number === '.' && this.currentOperand.includes('.')) return
this.currentOperand = this.currentOperand.toString() + number.toString()
}
``````

### chooseOperation(operation) function

We need to use the same technique we applied to the `numbers` buttons on `operation` buttons. However, instead of `appendNumber`, we will use `chooseOperation(button.innerText)` and update the display using `calculator.updateDisplay`.

The code will look like this:

``````operationButtons.forEach(button => {
calculator.chooseOperation(button.innerText)
calculator.updateDisplay()
})
})
``````

In the `chooseOperation()` function, we need to do some calculations.

When you click a number, followed by an operation on your calculator, you might want it to move up to the previous operand section for you to type in the other number to complete the entire operation.

For instance, if you want to compute `2 + 60 `, you may want the `2 +` portion to move into the `previous operand` section of the display so that `60` will be typed in the `current operand` section.

This operation can be implemented in the `chooseOperation()` function. The first thing to do is to set `this.operation` equal to the operation you passed. That way, your calculator is aware of what operation it desires to use when computing the value.

Then, you set `this.previousOperand = this. currentOperand` so you are essentially saying you are through typing the current number, so you recycle that over to the previous operand.

The new `current operand` also needs to be cleared by setting it to an empty string. You have to update your display. In the `updateDisplay()` function, add `this.previousOperandTextElement = this.previousOperand`.

If you go to your calculator and click any of the `operation` buttons, you will notice that they display even without clicking any number buttons.

We need to add a check-in for that. You can just say if the current operation is empty, then `return`, which again will not let you execute any further into your code.

One more thing that you can add to the calculator is the ability to compute an operation automatically while simultaneously completing another one.

For instance, if you type in `54 + 50` and then click on the `÷` button, the calculator should be able to compute `54 + 50`, making it `104` before dividing it automatically.

We can do this by checking whether the `previous` operand is not equal to an `empty` string and invoking the `this.compute()` method.

Here is what the code will look like:

``````chooseOperation(operation) {
if (this.currentOperand === '') return
if (this.previousOperand !== '') {
this.compute()
}
this.operation = operation
this.previousOperand = this.currentOperand
this.currentOperand = ''
}
``````

With these two functions completed, you can now set all the values inside the calculator. All we need now is to work on how to compute things and display things.

### compute() function

We should add an `EventListener` to the `Equals` button. The EventListener will invoke the `compute` function and return the results. We then need to update the calculator’s display. When you click the `Equals` button, it will call the `compute()` function.

Here’s the code linked to the Equals button:

``````equalsButton.addEventListener('click', button => {
calculator.compute()
calculator.updateDisplay()
})
``````

We can now perform the computation. The first thing you need to do is to create a variable that will store the result from the computation. We then need to create two extra variables. You’ll have a preceding variable, and this is simply going to be that actual number version of your previous operand.

You’re just converting this `string` to a `number`, and you will do the same thing with the `current` operand. For example, when the user clicks on the `Equals` button without clicking any button before it, you do not want the code to run. You can fix that this way.

You can say if it is not a number for previous, i.e., if it does not have a previous or current value, let it just `return`, which will cancel the function immediately. We will use a `switch` statement to determine or change the computation operation.

Here is the code for the `compute` function.

``````compute() {
let computation
const prev = parseFloat(this.previousOperand)
const current = parseFloat(this.currentOperand)
if (isNaN(prev) || isNaN(current)) return
switch (this.operation) {
case '+':
computation = prev + current
break
case '-':
computation = prev - current
break
case '*':
computation = prev * current
break
case '÷':
computation = prev / current
break
default:
return
}
this.currentOperand = computation
this.operation = undefined
this.previousOperand = ''
}
``````

Now, the calculator can perform calculations. However, you will find out that you cannot clear things out, and that is because you have not implemented the `All-Clear` button yet.

Here is the code to do that:

``````allClearButton.addEventListener('click', button => {
calculator.clear()
calculator.updateDisplay()
})
``````

Now you can use the `All-Clear` button on the calculator.

### delete() function

The last function to implement is the `delete()`. The first aspect you can do is to set `this.currentOperand = this.currentOperand`. We then convert this value to a `string` to get the last value of the string by using the `slice` method, as shown below.

``````  delete() {
this.currentOperand = this.currentOperand.toString().slice(0, -1)
}
``````

You can now hook that variable up by implementing the Delete button.

Below is the code to do that:

``````deleteButton.addEventListener('click', button => {
calculator.delete()
calculator.updateDisplay()
})
``````

Now, when you type a long string of characters, you can delete them one by one using the `Delete` button. The calculator is now fully functional, but the display still needs some work.

### updateDisplay function

The first thing you can do is to go into the `updateDisplay()` function and add an `if` statement. If we have an operation that is not null, then we will display the `previous` operand Text Element.

We then display both the `previous` and `current` operands, as shown below:

``````updateDisplay() {
if (this.operation != null) {
this.previousOperandTextElement.innerText =
`\${this.getDisplayNumber(this.previousOperand)} \${this.operation}`
``````

On your calculator, you may notice that when you type a string of numbers, there are no commas to make the numbers more definitive. Well, we can change that by using a helper function and calling it `getDisplayNumber(number)`. We will then display the returned value.

In short, we are going to add the `current` operand to the `updateDisplay()` function whenever it is invoked. Now, the changes you make in this function, are going to be mirrored in both the `previous` and the `current` operand values.

Here is how the entire `updateDisplay()` function code would look like:

``````  updateDisplay() {
this.currentOperandTextElement.innerText =
this.getDisplayNumber(this.currentOperand)
if (this.operation != null) {
this.previousOperandTextElement.innerText =
`\${this.getDisplayNumber(this.previousOperand)} \${this.operation}`
} else {
this.previousOperandTextElement.innerText = ''
}
}
}
``````

However, you will notice that numbers are not being formated correctly. This is because you need to make sure you use a `float` number in the `getDisplayNumber()` function instead of an `integer`, as shown below.

``````getDisplayNumber(number) {
const floatNumber = parseFloat(number)
if (isNaN(floatNumber)) return ''
return floatNumber.toLocaleString('en')
}
``````

We need to deal with a minor error. When you type in a value such as `0.0001`, it would not show up unless you click a different number like `0.2` or `0.3`.

This is because the value cannot be converted into a `float`. We can fix this by splitting the number you get into two: the integer part and the decimal part. We also eliminate unnecessary decimal points by setting the maximum fraction digits to zero, as demonstrated below:

``````getDisplayNumber(number) {
const stringNumber = number.toString()
const integerDigits = parseFloat(stringNumber.split('.')[0])
const decimalDigits = stringNumber.split('.')[1]
let integerDisplay
if (isNaN(integerDigits)) {
integerDisplay = ''
} else {
integerDisplay = integerDigits.toLocaleString('en', { maximumFractionDigits: 0 })
}
if (decimalDigits != null) {
return `\${integerDisplay}.\${decimalDigits}`
} else {
return integerDisplay
}
}
``````

Finally, we need to clear the `previous` operand value. This can be achieved by creating an `if-else` statement and checking if `this.previousOperandTextElement.innerText` is an empty string.

``````getDisplayNumber(number) {
if (decimalDigits != null) {
return `\${integerDisplay}.\${decimalDigits}`
} else {
return integerDisplay
}
}
``````

### Conclusion

While building the calculator, we used ES6 classes to organize our code. We also made use of vanilla JavaScript, CSS Grid, and Flexbox.

With that, you have a fully functional calculator. The source code of our application is available on GitHub.

Happy coding!

### Resources

Peer Review Contributions by: Wanja Mike