Let's build a basic calculator using flexbox and vanilla JavaScript
Tags: javascript, codenewbie, tutorial, css
Published: 2019-12-10 09:04:27

---
title: Let's build a basic calculator using flexbox and vanilla JavaScript
published: true
description: This beginner JavaScript project walks through the thinking and coding of a basic calculator using pure JS and CSS, with a working example at the end
canonical_url: https://www.chrisblakely.dev/how-to-create-a-basic-calculator-using-java-script
cover_image: https://images.unsplash.com/photo-1517694712202-14dd9538aa97?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1650&q=80
tags: 
 - javascript
 - codenewbie
 - tutorial
 - css
---


## Before we begin

Beginner JavaScript Project tutorials are a great way to learn and apply your knowledge. Rather than just show you how I do things, I'll explain WHY I do things. I recommend you try this yourself first, and see how I've done it by following along with the guide. There is a completed CodePen at the end. I will use [CodePen.io](CodePen.io) throughout the tutorial but you can use your IDE if you like. Enjoy!

## What we're building

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/vp1zjao8dq8mcaw5n4u4.gif)

This is the amazing calculator we will be building. We can input numbers, add, subtract, multiply and divide, as well as reset the display. Isn't it marvellous?

## Build the UI

Let's start by adding the UI. This helps us visualise things as we go, such as user interactions and state changes.

### Add a Container

In your HTML section add the following:

```html
<div class="container">

</div>

```

and in your CSS section add the following:

```css
.container{
    background: lightGrey;
    width: max-content;
    margin: auto;
}
```

You won't see anything yet but all we're doing here is adding a container, which gives us better control and structure of the calculator elements which we'll add later. We're also giving it a width (we want it to expand to fit the content), a background color, and centering everything in the view. 

### The display

When building the UI, can you build it however you like - For something like this I like to work "top-down", so I'll start with the display. This displays the calculations and results to the user and goes at the top of our container.

It makes sense for the display to be it's own element (so we can style it, and identify it clearly in the code/browser inspector). We'll create a separate `div` for this and also hard code a dummy value (`989`), so we can visually see what the display will look like, which should make it easier to style.

Add the following to your HTML, just inside the container:

```html
  <div class="display">989</div>
```

The completed HTML so far should look like this;

```html
<div class="container">
  <div class="display">989</div>
</div>
```

And add the following to your CSS:

```css
.display{
  width: 100%;
  background-color: darkGrey;
  height: 50px;
}

```

All we're doing here is making sure the display isn't too big (`height: 50px`), takes up the width of the container (`width: 100%`) and has a background color that differs from the container. 

So far, our project should look like this:


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/0mtm652fc0rjv3wheaap.png)

We still have some work to do. The number appears at the top left, we want it to appear towards the right-hand side of the display, and have a bigger font-size. 

> When we need to arrange items, in a single direction (e.g horizontally or vertically) *Flexbox* is a good option, so we'll use that here to style our display input.

Amend the `.display` style in your CSS with the following:

```css
.display{
    width: 100%;
    background-color: darkGrey;
    height: 50px;
    font-size: 48px;
    display: flex;
    justify-content: flex-end;

}

```

Note the bottom 2 lines - `display:flex` and `justify-content: flex-end;`. This means that the display *is a flex container* and that it's children (in this case, the text content, i.e the number) *should align to the END (the right side) of the container*. Lastly, we're making the font bigger.

With our fancy flexbox stuff added, the display should look like this:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/atap782vg37587wixq0i.png)

If you add more numbers to the dummy text, the inputted number stays justified to the right of the container (this is thanks to our `flex-end`)

### Add the buttons

Now that we have our display in place and formatted, it's time to add the buttons - this would be a pretty useless calculator otherwise!

We'll add a container div to hold our buttons - remember, adding a `container div` around related items makes it easier to manage/style related elements, and makes our code easier to read. We'll also add our buttons, in order of left-to-right (like we were reading a book) to match our design. We'll use `flexbox` to arrange the buttons later.

Go ahead and update your HTML so that it looks like this: 

```html
<div class="container">
    <div class="display">989</div>
    <div class="buttons">
        <button class="btn-number">1</button>
        <button class="btn-number">2</button>
        <button class="btn-number">3</button>
        <button class="btn-operator">+</button>
        <button class="btn-number">4</button>
        <button class="btn-number">5</button>
        <button class="btn-number">6</button>
        <button class="btn-operator">-</button>
        <button class="btn-number">7</button>
        <button class="btn-number">8</button>
        <button class="btn-number">9</button>
        <button class="btn-operator">X</button>
        <button class="btn-clear">C</button>
        <button class="btn-number">0</button>
        <button class="btn-equals">=</button>
        <button class="btn-operator">/</button>
    </div>
</div>
```

Note that the number buttons have a class `btn-number`, operator buttons have a class `btn-operator`, the equals button has a class `btn-equals` and the clear button has a class of `btn-clear`. We'll use these classes to style the buttons later.

So our buttons are in, but the layout is wrong and they look a bit crappy.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/al4jf4r93ehi1umr2ugf.png)

The reason why we arranged our buttons in a single row like this is that we can use `flexbox` to control the layout. Remember, our buttons are wrapped in a `buttons` div, so we will make this our `flex container`. Update the `.buttons` CSS to include the following:

```css

.buttons{
    max-width: 400px;
    display:flex;
    flex-wrap: wrap;
}

```

Ok so what's happening here?

- We're setting our `buttons` div to be a `flex container`
- We're setting the width to be `400px`;
- We're saying that we want the *items* of the flex container (i.e, our buttons) to *wrap* (i.e take a new line). This will happen when the length of the row, goes over 400px (our width).

You should now see this:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/dgmnnc0ibo6747af8agg.png)

Now I know what you're thinking: "Chris, WTF? I'm setting up all this stuff and nothings working". Yes, but stay with me, the magic is about to happen. We've merely set up our *flex container layout*, now we need to add some properties to our *flex items* i.e buttons.

Add the following to your CSS:

```css

button{
  flex: 1 25%;
} 

```

Our calculator should now look like this:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/0hdale1gf065lz8uyebv.png)

If you were WTF'ing before, you still might be now, but in a more curious tone. Let's explain what just happened when we added `flex: 1 25%` to each button:

This is shorthand syntax for `flex-grow: 1` and `flex-basis: 25%`, e.g, our `button` CSS above could be rewritten like:


```css

button{
  flex-grow: 1; 
  flex-basis: 25%;
} 

```

This means "each item (i.e button) should take up 25% of the space available, and the item itself should grow to fill said space". Let's do some maths to explain further. Remember, our `container` has a `max-width of 400px`. We've told the container *any overflowing items should break onto the next line* by using `flex-wrap: wrap`. 

This means we have *400px of space per row* before a line break happens. Since we've said that *each button should take up 25% of the space available*, each button should have a width of `100px` (since 25% of 400px is 100px) giving us 4 buttons per row. By inspecting the dev tools, we can see this is true:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/0hdale1gf065lz8uyebv.png)

If we wanted 2 buttons per row, we should change the *percentage* in our CSS:

```css
button{
  flex: 1 50%;
} 

```

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/jlxaz74e52tsdkk8l1f1.png)

### Why do we need to do this?!

This makes it easier to align/arrange items in a few lines of code. If you look at our HTML and CSS, there isn't very much there. Should our design change in the future (e.g change of button layouts, more responsive design, etc) it will be less complex to change.

> I encourage you to stop here and play about with some of the `flex` properties we talked about, so you really understand what's going on. Have a look at [This Guide To Flexbox on CSS-Tricks](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) for reference. It's amazing. I'm going to get a coffee while you do that, then we'll get into JavaScript mode!

Let's wrap up our UI by adding some styling to the buttons. Add the following to your CSS:

```css
button{
  flex: 1 25%;
  padding: 15px;
  font-size: 26px;
} 

.btn-number {
  background-color:grey;
}

.btn-operator {
  background-color:orange;
}

.btn-equals {
  background-color:green;
}

.btn-clear {
   background-color:crimson;
}

```

And let's remove the dummy data in the display. In your HTML, remove the `989` value from the div:

```html
  <div class="display"></div>
```

Our finished UI should look like this:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/y32xoi99ix5p1epyaf2g.png)

Look at our amazing calculator! It looks nice but does nothing yet. So let's get everything wired up.

NOTE: See the CodePen at the bottom to see the completed HTML/CSS if you're having issues.

## Add the JavaScript

When you're starting the JavaScript-y parts of a project, it can be hard to know where to start. I like to begin by thinking about what functionality I need, and making a list (this is why I built the UI first, so it's easier to visualize the functionality).

> Why not take this time to come up with a list of functionality, and compare it to my list below? 

Ready? Ok good, here's my list:

- When the user clicks a number or operator button, the display should update with the value of the button
- When the clear button is clicked, the display should reset/clear
- When the equals button is clicked, the display should update with the result of the equation that is displayed

There's probably other stuff I missed that you think is important - you can always expand on this code later to add your own stuff!


## Update the display when a number or operator button click

This is a good place to start, we'll worry about the other stuff later. Let's think more about how our JavaScript is going to look before jumping into the code.

> "when a button is clicked, the display should update with the value of the button"

Some things that jump out when re-reading that functionality:

- We'll need to get all the buttons and their values from the DOM
- We'll need to add an event listener to handle the clicks
- We're updating the display, so we'll need to get the display from the DOM as well

That should be enough to get us going! Let's start by updating the display when an `operator button` or `number button` is clicked. We will handle the clear and equals later.

> *Why are the equals and clear buttons code separate? Can I not get all the buttons at once and add all the event listeners at once?*

The answer is yes, you can do whatever you want as there is no "right" way to write code. However, splitting the code out in this way has a few advantages:

- It keeps similar logic together, enforcing good separation of concerns for our functions
- If we have to add more buttons & logic, we don't touch existing code
- It makes the code easier to read & reason about; it's easier to see which buttons do what

### Get the number & operator buttons from the DOM

Add the following to your JS section in CodePen (or to your JavaScript script if you're using an IDE):

```js

const buttons = document.querySelectorAll('.btn-number, .btn-operator')
const display = document.querySelector('.display')

```

All we're doing here is using `querySelectorAll` to get our `buttons` (number buttons and operator buttons) and get our `display`. 

>, In this case, it's a good idea to assign DOM elements to top-level variables, as it makes it easier for us to access these elements without having to repeatedly use `document.querySelectorAll()` throughout the code. It also helps if the `querySelector` changed for some reason (e.g from `.display` to `.calculator-input-display`), as we only have to change the `querySelector` in one place!

Next, we're going to add a `data-num` attribute to the HTML of our buttons, which will hold the *value of that button*. Update your HTML to match the following:

```html
<div class="container">
  <div class="display"></div>
  <div class="buttons">
    <button class="btn-number" data-num="1">1</button>
    <button class="btn-number" data-num="2">2</button>
    <button class="btn-number" data-num="3">3</button>
    <button class="btn-operator" data-num="+">+</button>
    <button class="btn-number" data-num="4">4</button>
    <button class="btn-number" data-num="5">5</button>
    <button class="btn-number" data-num="6">6</button>
    <button class="btn-operator" data-num="-">-</button>
    <button class="btn-number" data-num="7">7</button>
    <button class="btn-number" data-num="8">8</button>
    <button class="btn-number" data-num="9">9</button>
    <button class="btn-operator" data-num="*">X</button>
    <button class="btn-clear">C</button>
    <button class="btn-number" data-num="0">0</button>
    <button class="btn-equals" data-num="=">=</button>
    <button class="btn-operator" data-num="/">/</button>
  </div>
</div>
```

> *"Why do we need to do this?! Why can I not get the value from the button text?"*

Good question! This technique is used to *separate data from presentation*. Take the example of the multiply sign:

```html
    <button class="btn-operator" data-num="*">X</button>
```

The text of the button is `X` but the value is actually `*`, since this is how we multiply in JavaScript. Using this approach means the text can be whatever we want, but the *value* never changes. e.g:

```html
<!-- If we ever change the text of any of the buttons, the value stays the same  -->
<button class="btn-operator" data-num="*">X</button>
<button class="btn-operator" data-num="*">Multiply</button>
<button class="btn-operator" data-num="*"><img src="link-to-multiply-image"/></button>
```

OK! So we've stored the data for each button and got the DOM elements. Next, let's handle what happens when a button is clicked.

### Add the event listeners

When we use `querySelectorAll()`, this returns a `NodeList` (this is basically a list of matching elements, which we can loop over). This means we can loop over our `buttons` variable and attach an `onClick listener`.

Add the following to your JavaScript:

```js
const buttons = document.querySelectorAll('.btn-number, .btn-operator')
const display = document.querySelector('.display')

//add an eventListener to each of the buttons
buttons.forEach(button => {
  button.addEventListener('click', () => { 
      // logic that run when the button is "clicked"
      alert("button was clicked!")
  })
})

```

As you can hopefully see, we're using the `forEach()` higher-order function to loop over the buttons that were returned from our `querySelectorAll()` function. 

For each `button` we are adding a `click eventListener`. When a button is clicked, it should show an alert box:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ebqhoyve3i85g3ento9q.png)

Hurray! Success! 

(If you're having issues and not seeing the alert box, check out the CodePen at the end of the article to see the finished solution).

### Get the value of the button that was clicked

Next, we need to get the value of the clicked button from the `data-num` attribute we added earlier. When we want to get *attributes* from DOM elements, we can use the `getAttribute(name)` function. Add the following to the event listener logic in your JavaScript:

```js
const buttonValue = button.getAttribute('data-num');  
alert(buttonValue + " was clicked!")
```

The JavaScript so far looks like this:

```js
const buttons = document.querySelectorAll('.btn-number, .btn-operator')
const display = document.querySelector('.display')

//add an eventListener to each of the buttons
buttons.forEach(button => {
  button.addEventListener('click', () => { 
    // logic that run when the button is "clicked"
    const buttonValue = button.getAttribute('data-num');  
    alert(buttonValue + " was clicked!")
  })
})

```

When you click a button, the alert should show the *value of the button that was clicked*.

### Update the display

Now that we have working event handlers, and can get the value of the button that was clicked, we can start updating our display.

Remember, it's good practice to *separate data from presentation* whenever possible. So let's create a variable called `displayData` to hold the *data* for our display. In your JavaScript add the following:

```js

let displayData = "";

```

and update the `eventListener logic` by replacing the `alert` with this line:

```js
displayData += buttonValue;
alert("Display is now: " + displayData)
```

The completed JavaScript so far looks like this:

```js

//get our buttons from the DOM
const buttons = document.querySelectorAll('.btn-number, .btn-operator')
const display = document.querySelector('.display')

let displayData = "";

//loop over the buttons
buttons.forEach(button => {

    //for each button, we want to add a "click" event listener
    button.addEventListener('click', () => { 

        //get the value of the clicked button from the attribute
        const buttonValue = button.getAttribute('data-num');

        //update our displayData variable with the value of the clicked button
        displayData += buttonValue;
        alert("Display is now: " + displayData)
    })
})

```

Now when you click a button, you will see an alert with the equation displayed! 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/y37tll2jln6rxdwzzz7x.png)

Now we know what our `displayData` successfully updates when a button is clicked, we can go ahead and update the actual display with this data. Remove the `alert` in your event listener and add the following:

```js
display.textContent = displayData;
```

Now, our display should update when a number or operator button is clicked:


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/tpgx2w8wcqq5aglkol19.png)

Woohoo! Looking good so far, but you will have noticed the equals and clear buttons do not work yet. So let's wire those up.


## Update the display with the result

If we take some time to think about what we need to do here, it'll make our life easier when writing the code.

- We need to get the *equals button* from the DOM
- When the button is clicked, we want to *evaluate* the expression that is displayed
- We want to show the result of the expression in the display

> Why not try this next part yourself first before following on? HINT: We've used similar patterns already, referencing other code for help is a good way to solve problems!


### Get the Equals button from the DOM

Just like before, we will get the `equals button from the DOM`. Add the following to your JavaScript:

```js
const equalsButton = document.querySelector('.btn-equals')
```

Notice we use `querySelector` here instead of `querySelectorAll` as we know there is only one element with this selector. `querySelector` returns a single element instead of a `NodeList` which means we don't need to use a loop!

Next we'll add an `eventListener`, and use the `eval()` function to *evaluate the displayData expression*. We'll set this evaluated expression to our `displayData` variable, and update our display:

```js
equalsButton.addEventListener('click', () => { 
    displayData=eval(displayData)
    display.textContent = displayData
})
```

The complete JavaScript so far looks like this:

```js 
//get our buttons from the DOM
const buttons = document.querySelectorAll('.btn-number, .btn-operator')
const equalsButton = document.querySelector('.btn-equals')
const display = document.querySelector('.display')

let displayData = "";

//loop over the buttons
buttons.forEach(button => {

    //for each button, we want to add a "click" event listener
    button.addEventListener('click', () => { 

        //get the value of the clicked button from the attribute
        const buttonValue = button.getAttribute('data-num');

        //update our displayData variable with the value of the clicked button
        displayData += buttonValue;

        //output the displayData value to the display element
        display.textContent = displayData;
    })
})

// add an event listener to the equals button
equalsButton.addEventListener('click', () => { 

    // use the eval() function to evaluate the expression and output it to the display
    displayData=eval(displayData)
    display.textContent = displayData
})

```

And that's it - if you perform an equation e.g "2+2", you should see the result in the display.

### Clear the display 

The last thing we need to do is clear the display when the `C` button is clicked. Just like before, we will get the `clear button` from the DOM. Add the following to our JavaScript:

```js
const clearButton = document.querySelector('.btn-clear')
```

And add our eventListener:

```js
clearButton.addEventListener('click', () => { 
  displayData = "";
  display.textContent = displayData;
})
```

Here, we are *resetting our displayData variable to empty string*, which effectively clears the display. Finally, we're updating our display in the usual way. 

If all went well, you should have a fully working calculator! If not, check out the CodePen at the bottom so see the finished example.

## Thing's to Try

Before we wrap up, here are some thing's you can try:

- The numbers will overflow if the user types in too many numbers, how would you fix this?
- The calculator won't work correctly if the user enters too many operators, e.g `2++2`.  How can you prevent the user from doing this?
- Why not try adding an undo feature?


## Finished Example

<iframe height="500" style="width: 100%;" scrolling="no" title="simple-js-calculator" src="https://codepen.io/chrisblakely01/embed/gOOqxgN?height=265&theme-id=default&default-tab=js,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
  See the Pen <a href='https://codepen.io/chrisblakely01/pen/gOOqxgN'>simple-js-calculator</a> by Chris Blakely
  (<a href='https://codepen.io/chrisblakely01'>@chrisblakely01</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>

## Thanks for reading!

If you enjoyed this article, why not [subscribe to my newsletter](subscribe.chrisblakely.dev)?

Every week I send out a list of 10 things I think are worth sharing — my latest articles, tutorials, tips and interesting links for upcoming developers like you. I also give out some free stuff from time to time :)