If you want to know more about how this starter project came to be, you can read more in my post on how to make your own TypeScript starter project.
You can see the finished hosted version of this calculator on Netlify.
The markup is very simple. The root element will be a custom element called <ws-calculator>. Inside this, there will be a display section and a button section.
The styling is straightforward but uses a CSS grid for the buttons. This allows you to nicely position the ‘=‘ button over two rows.
The calculator will be a custom element called
ws-calculator. This means you need to start with a class that extends the HTMLElement class.
If you’re following along with the TypeScript starter project, this should go in
The class needs to keep track of several things:
- The display element
- The button elements
- The current query to calculate
Let’s create several properties to hold this data. Additionally, let’s create a getter and setter for the query property. This allows you to perform extra logic when the query changes.
Now that the class can take care of the data, you need to set up the event listeners for the button clicks. Custom elements have two automatically invoked functions that will be useful in this project:
- connectedCallback — this function is invoked each time the custom element is appended into a document-connected element.
- disconnectedCallback — this function is invoked each time the custom element is disconnected from the document’s DOM.
The event listeners should be bound on the connectedCallback and unbound on the disconnectedCallback. This will prevent events to be double-bound if the calculator is moved or re-added.
Handling the button click
When you click on any button, it will trigger the
handleButtonClick method. We should determine the value of the button, but also the user value. For example, the * sign is used to perform multiplication, but on the display, you want to show the ‘x’ character.
Most buttons should add a character to the display. However, there are three buttons that have different functions:
- The AC button should clear the display.
- The CE button should remove the last character from the display.
- The = button should perform a calculation.
Let’s implement a simple switch statement to handle these different inputs.
performCalculation doesn’t exist yet, let’s add it as an empty function for now.
Updating the display
query property is now updated when buttons are clicked, but they aren’t updated on the screen yet. Let’s create a method to update the display and call the method from the
query setter method.
You should now have an almost working calculator that updates the display, can clear the display and can remove the last character. It’s time to implement the final function to perform a calculation.
Performing the calculation
There are many ways to perform a calculation based on our query. We could parse the values in between the operators and perform logic to calculate the outcome. For the purposes of this tutorial, the
eval() method will be used.
eval() method is a global function property that takes a string as an argument. If the string in question represents an expression, the expression is evaluated and the result is returned.
It is not advised to use eval in a production setting since it can pose security risks if third parties can alter the string. But for this simple tutorial, it is safe to use.
This marks the end of the tutorial. You have just build a fully functioning calculator using TypeScript and the custom elements spec.
The GitHub repository contains the full code for this project if you want to take a look.