Build a Sleek, Modern Calculator with Vue.js 3 and CSS Grid

Building a calculator is often one of the first projects you tackle when learning a new JavaScript framework. It's the perfect exercise: it combines state management (tracking numbers and operations), UI logic, and event handling. But why stop at a basic, functional calculator? In this article, we'll not only build the logic for a calculator using Vue.js 3 and its fantastic Composition API, but more importantly, we'll give it a modern, professional look inspired by a popular design, leveraging the power of CSS Grid. The final result is live here, and all the code is available in this GitHub repository: ➡️ https://github.com/VincentCapek/calculator Step 1: Setting Up the Vue.js Project To get started, nothing beats Vue's official project scaffolding tool: npm create vue@latest For this project, we don't need complex features like Vue Router or Pinia. I simply enabled ESLint and Prettier to ensure clean, consistent code. Once the project is created, navigate into the directory, install the dependencies, and start the development server: cd your-project-name npm install npm run dev We'll be working in a single file for this entire tutorial: src/App.vue. Step 2: The Calculator Logic with the Composition API This is the "brain" of our application. Thanks to the Composition API and the syntax, our logic is both reactive and highly readable. We need a few state variables to keep track of what's happening: import { ref } from 'vue'; // The main display of the calculator const current = ref(''); // The previous number, stored after an operator is clicked const previous = ref(null); // The selected operator (+, -, etc.) const operator = ref(null); // A flag to know if an operator was just clicked const operatorClicked = ref(false); ref() is Vue 3's way of creating reactive variables. Whenever their .value changes, the UI updates automatically. It's like magic! Next, we define the functions that bring our calculator to life: clear(): Resets everything. This is our "AC" button. append(char): Adds a digit or a decimal point to the current value. setOperator(op): Stores the current value, saves the operator, and gets ready for the next number. calculate(): Performs the calculation and updates the display. Here's the complete script, which also includes a little bonus: handling division by zero. import { ref } from 'vue'; const current = ref(''); const previous = ref(null); const operator = ref(null); const operatorClicked = ref(false); const clear = () => { current.value = ''; previous.value = null; operator.value = null; operatorClicked.value = false; }; const append = (char) => { if (operatorClicked.value) { current.value = ''; operatorClicked.value = false; } if (char === '.' && current.value.includes('.')) return; current.value = `${current.value}${char}`; }; const setOperator = (op) => { if (current.value === '') return; if (operator.value !== null) { calculate(); } previous.value = current.value; operator.value = op; operatorClicked.value = true; }; const calculate = () => { if (operator.value === null || previous.value === null) return; let result; const prev = parseFloat(previous.value); const curr = parseFloat(current.value); // Handle division by zero if (operator.value === '÷' && curr === 0) { current.value = 'Error'; previous.value = null; operator.value = null; return; } switch (operator.value) { case '+': result = prev + curr; break; case '-': result = prev - curr; break; case 'x': result = prev * curr; break; case '÷': result = prev / curr; break; } current.value = String(result); previous.value = null; operator.value = null; }; Step 3: The HTML Structure (The Skeleton) For better semantics and accessibility, we'll use appropriate HTML elements: An for the display screen. Real elements for all the keys. The template is directly tied to our logic. Notice how we call the functions with arguments directly from the @click event handler, which is a clean and robust approach. + 7 AC =  Step 4: The Magic of CSS (The Design) This is where our calculator truly comes to life ! 1. The Background and "Glassmorphism" Effect The page body gets a beautiful linear gradient, while the calculator itself has a semi-transparent background with a backdrop-filter. This creates the trendy "glassmorphism" effect, making it look like frosted glass. body { background: linear-gradient(to right, #6190e8, #a7bfe8); } .calculator { box-shadow: 0 0 40px 0px rgba(0, 0, 0, 0.15); background-color: rgba(255, 255, 255, .75); backdrop-filter: blur(5px); } 2. A Perfect Layout with CSS Grid The button layout is managed with display: grid, making it robust and easy to maintain. grid-gap creates a uniform

Jun 9, 2025 - 22:10
 0
Build a Sleek, Modern Calculator with Vue.js 3 and CSS Grid

Building a calculator is often one of the first projects you tackle when learning a new JavaScript framework. It's the perfect exercise: it combines state management (tracking numbers and operations), UI logic, and event handling.

But why stop at a basic, functional calculator? In this article, we'll not only build the logic for a calculator using Vue.js 3 and its fantastic Composition API, but more importantly, we'll give it a modern, professional look inspired by a popular design, leveraging the power of CSS Grid.

The final result is live here, and all the code is available in this GitHub repository:
➡️ https://github.com/VincentCapek/calculator

Preview of the final calculator

Step 1: Setting Up the Vue.js Project

To get started, nothing beats Vue's official project scaffolding tool:

npm create vue@latest

For this project, we don't need complex features like Vue Router or Pinia. I simply enabled ESLint and Prettier to ensure clean, consistent code.

Once the project is created, navigate into the directory, install the dependencies, and start the development server:

cd your-project-name
npm install
npm run dev

We'll be working in a single file for this entire tutorial: src/App.vue.

Step 2: The Calculator Logic with the Composition API

This is the "brain" of our application. Thanks to the Composition API and the

Step 3: The HTML Structure (The Skeleton)

For better semantics and accessibility, we'll use appropriate HTML elements:

  • An for the display screen.
  • Real

The template is directly tied to our logic. Notice how we call the functions with arguments directly from the @click event handler, which is a clean and robust approach.


 Step 4: The Magic of CSS (The Design)

This is where our calculator truly comes to life !

1. The Background and "Glassmorphism" Effect

The page body gets a beautiful linear gradient, while the calculator itself has a semi-transparent background with a backdrop-filter. This creates the trendy "glassmorphism" effect, making it look like frosted glass.

body {
  background: linear-gradient(to right, #6190e8, #a7bfe8);
}

.calculator {
  box-shadow: 0 0 40px 0px rgba(0, 0, 0, 0.15);
  background-color: rgba(255, 255, 255, .75);
  backdrop-filter: blur(5px);
}

2. A Perfect Layout with CSS Grid

The button layout is managed with display: grid, making it robust and easy to maintain. grid-gap creates a uniform spacing between each button.

.calculator-keys {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-gap: 20px;
  padding: 20px;
}

3. The Spanning "Equals" Button

The highlight of this design is the = button, which spans multiple rows. This is incredibly simple to achieve with the grid-area property. The syntax grid-area: row-start / col-start / row-end / col-end; gives us complete control.

.equal-sign {
  /* Starts on grid row 2, column 4, and spans down to row 6, column 5 */
  grid-area: 2 / 4 / 6 / 5;
  height: 100%;
}

4. Hover Effects that Respect Contrast

This is a crucial UX detail. A generic grey :hover state on all buttons would ruin the design of the colored ones (white text on a light grey background is nearly unreadable). The solution is to define specific hover states for each button type, simply by making their base color slightly lighter.

/* Hover for numeric buttons */
button:hover {
  background-color: #f0f0f0;
}

/* SPECIFIC hover for operators */
.operator:hover {
  background-color: #469dcb; /* A lighter blue */
}

/* SPECIFIC hover for the "AC" button */
.all-clear:hover {
  background-color: #f26f74; /* A lighter red */
}

Conclusion

And there you have it! We've built a calculator that is not only functional, thanks to the reactive power of Vue.js 3, but is also visually stunning using modern CSS techniques.

This project is a great example of how fundamentals are key, but with a bit of attention to design and user experience, you can turn a simple learning exercise into a portfolio piece you can be proud of.

Thanks for reading, and happy coding !