Building A Product List Page With Vue 3 And Vite

 · 13 min · Nasir

Lets learn how to use Vue 3, the composition API, script setup, pnpm and Vite.

tutorial vue vitejs

What a beautiful day to learn a new framework! In this post, let us delve into the world of Vue, specifically Vue 3. I will oversimplify the explanation of technologies used in this tutorial to focus on the good stuff: creating a functional website. However, if you want further reading regarding any topics, links to their documentation will be provided.


There are a couple of ways to use Vue 3 in your project, just as mentioned in their guide. I have chosen to use Node to set up our workspace for this post.


Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine.

If you are familiar with Javascript, you would have probably heard of Node. It is the building block of many websites in the world today. Created by Ryan Dahl, this technology allows you to extend the functionalities of your website exponentially.

Specifically, I will install Node because of the Node Package Manager or npm. It is to install vast amounts of frameworks such as React, Svelt, Angular and, of course, Vue.

To install Node, you can just follow the instructions on their website. In a nutshell, you would need to download the installer, run it, agree to all conditions and restart your computer when prompted.

Install PNPM

I am a user of pnpm because I feel that it is a more efficient and fast package manager. To install globally on your computer, open your command prompt and run the following:

npm install -g pnpm

You can check out their documentation here.

Vue 3

Javascript frameworks exist to simplify web development. Vue 3 is lightweight and has an easy-to-understand syntax. The ability to split your website into functional components makes the overall development experience much more enjoyable. You can also save time significantly by focusing more on your website logic rather than the complexities of manipulating DOM elements. Here is a simple difference when adding two numbers

  • Vanilla JS
<p id="demo"></p>

  document.getElementById('demo').innerHTML = 2 + 2;
  • Vue
<p>{{ 2 + 2 }}</p>


Vue is a language that is unrecognizable for the browser. Therefore, the ‘bundling’ of code is required to view the result. For this project, I will use Vite (a French word for “quick”, pronounced /vit/, like “veet”) for one simple reason; it’s fast.

If you are familiar with webpack or Rollup, try Vite. You will feel the difference. More about how Vite is created to solve problems here.

What we are building

Today, I will build a sortable product list using different criteria to showcase creating a website with Vue. Here is a preview of the website:

And here is the link to the repository:

Create a Vite project

First, create a folder or use an existing folder for this project. For example, I will be using the C:\Websites\ folder. Open the command prompt and direct to this folder. If you are on Windows, you can type cmd in the address bar in the C:\Websites\ folder.

Type cmd
Type cmd and click enter

The command prompt will display something like this based on what you name your folder.


This command will create a new folder for this post:

pnpm create vite product-sorter-vue3 -- --template vue

product-sorter-vue3 is replaceable with any name that you prefer.

After the project is scaffolded, run the following command to go inside the folder you just created:

cd product-sorter-vue3

Then run this to install all dependencies:

pnpm i

Once its done, run this command to run a development server:

pnpm dev

Then you can go to http://localhost:3000/ to view this:

Vue Vite Starter
Congratulations, you have created your Vue 3 with Vite Project

As you can see in the preview, it is recommended to use VSCode and Volar, an extension in VSCode, for syntax highlighting and a better Vue 3 development experience.

To stop the dev server, click ctrl + c, then type Y to confirm. At the same folder and if you are on Windows, you can type

code .

to open this project in VSCode (already installed). For Mac users, you can check out this documentation.

Vite by Anthony Fu
You can also install an extension called Vite by Anthony Fu which will auto start your dev server without typing pnpm dev. Check the terminal to see the address that it is running on, for me it is http://localhost:4000/. To stop and restart the server, you can just click the Vite symbol at the bottom to toggle.

Single Page Application (SPA)

Vue is a framework that is originally created as a Single Page Application or SPA. This means that it only serves a single index.html document. All of the functions and page route is manipulated by javascript. We can see this structure when we go to index.html:

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>

As declared in index.html, main.js is the javascript file that takes over the whole document. Vue is initialized in this file and looks like this:

import { createApp } from 'vue'
import App from './App.vue'


Vue Structure

All vue structure has 3 major tags in a Single File Component (SFC):

  1. <script> This is the place where you write most of your logic in javascript or typescript.

  2. <template> Normal html tags apply here.

  3. <style> This is where you keep the CSS for the SFC. If you wish to make the style apply to the current elements only, add <style scoped>

Check out App.vue for a sample:

<script setup>
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
import HelloWorld from './components/HelloWorld.vue'

  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Hello Vue 3 + Vite" />

#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;

For this post, I will focus on the <script setup> Composition API rather than the traditionally used Options API. Some advantages are as follows:

  • Concise code with less boilerplate
  • Ability to declare props and emitted events using pure TypeScript
  • Better runtime performance
  • Better IDE type-inference performance

Check out the documentation here for a full description. All in all, I believe that the composition API is much easier to write code, has typescript support and is more manageable in the event of your code getting bigger.

If you wish to use typescript, add <script setup lang="ts">


Hello World

Notice the HelloWorld component being imported and used in the template. As your website grows, more components will be imported and manipulated in various ways.

When information is passed inside a component, it is called a prop. When data is coming from the component to be received by the parent, its called an emit.

In App.vue, the string Hello Vue 3 + Vite is passed as a prop. The name of the prop is msg. And if we go to HelloWorld.vue inside the components directory, we can see how this prop is received:

defineProps({ msg: String })

Now, you can call the prop inside the template like so:

<h1>{{ msg }}</h1>

Pretty simple right?


In Vue, event-handling is using a v-on directive. It is usually shortened to just the @ symbol. Let us now look at the button that increases by 1 at every click. To implement this, ref is imported to make the count variable reactive. This is done in the <script setup>:

import { ref } from 'vue'
const count = ref(0)

Then, in the template, a click event is added to a button to signify that the count value to increase by 1 at every click.

<button type="button" @click="count++">count is: {{ count }}</button>

Read more about Javascript Operators Reference here.

Now, I will delete the HelloWorld.vue component and the contents of App.vue to start creating our project.


Script Setup

First, I will import ref and also a ProductList component (to be created later):

import { ref } from 'vue'
import ProductList from './components/ProductList.vue'

Then I will generate random products to use in this demonstration:

const products = ref([
  { title: 'Phone', colour: 'Grey', price: 549, id: 1 },
  { title: 'Mechanical Keyboard', colour: 'Blue', price: 79, id: 2 },
  { title: 'LCD Monitor', colour: 'Black', price: 127, id: 3 },
  { title: 'Desktop', colour: 'Red', price: 2132, id: 4 },
  { title: 'Laptop', colour: 'White', price: 1264, id: 5 },

I will also create a variable for the sorting order. The default value is title:

const orderBy = ref('title')

Then, the function to fire when we click on a different term:

const handleClick = (term) => {
  orderBy.value = term


The main title:

<h1 class="title">The Store</h1>

The buttons to sort the products

<div class="orders">
  <button @click="handleClick('title')">Title</button>
  <button @click="handleClick('colour')">Colour</button>
  <button @click="handleClick('price')">Price</button>

The component that shows a list of products that we will create

<ProductList :products="products" :orderBy="orderBy" />


Finally, just some styling to make this demonstration looks a little more presentable:

@import url('https://fonts.googleapis.com/css2?family=Corinthia:wght@700&display=swap');
html {
  background-color: whitesmoke;
#app {
  font-family: Verdana, Geneva, Tahoma, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
  margin: 60px auto;
.orders {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
  max-width: 90%;
  margin: 0 auto;
@media (min-width: 600px) {
  .orders {
    max-width: 600px;
.orders button {
  margin: 2px;
  padding: 20px;
  cursor: pointer;
  font-weight: bold;
  border-radius: 10px;
  color: #2c3e50;
  background-color: rgb(255, 247, 203);
  box-shadow: lightslategray 0 1px 2px;
  border: none;
  transition: all ease 0.3s;
.orders button:hover {
  background-color: rgb(241, 237, 212);
.title {
  color: gold;
  text-shadow: 2px 2px #2c3e50;
  font-family: 'Corinthia', cursive;
  font-size: 100px;
  margin: 0;



Inside the components folder, I will create a ProductList.vue to handle the props received from App.vue. First, I will import the computed function to create a function to sort the products:

import { computed } from 'vue'

Then, define the props received from App.vue

const props = defineProps({ products: Array, orderBy: String })

Lastly, I create a function to sort the products in different order terms like so:

const orderedProducts = computed(() => {
  return [...props.products].sort((a, b) => {
    return a[props.orderBy] > b[props.orderBy] ? 1 : -1


The template is fairly straightforward. A line to inform of the current sorting term:

<p>Sort by: {{ orderBy }}</p>


In Vue, we can loop through an array using the v-for loop and extract each element like this:

<div class="product" v-for="product in orderedProducts" :key="product.id">
  <h1>{{ product.title }}</h1>
  <p>{{ product.colour }}</p>
  <p>${{ product.price }}</p>


Then I will wrap the loop with a <transition-group> for the animation. If you were to animate a single div, you can use <transition> to achieve that. I will name my animation sorter. You can name your animation to whichever you prefer.

<div class="product-container">
  <transition-group name="sorter">
    <div class="product" v-for="product in orderedProducts" :key="product.id">
      <h1>{{ product.title }}</h1>
      <p>{{ product.colour }}</p>
      <p>${{ product.price }}</p>


After that, I will declare the styles for this SFC like so:

.product-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
.product {
  height: 100%;
  width: 40%;
  padding: 10px 0;
  margin: 5px;
  box-shadow: lightslategray 0 1px 2px;
  border-radius: 10px;
  background-color: #fdfdfd;
.product h1 {
  font-size: large;
.sorter-move {
  transition: all 1s;

Notice that the .sorter-move class is defined just to show the movement when the products are sorted. Other than -move, you can also add other classes in Vue for animation such as:

  1. v-enter-from
  2. v-enter-active
  3. v-enter-to
  4. v-leave-from
  5. v-leave-active
  6. v-leave-to

You can read more about animating in Vue 3 in the following link.

Wrapping it up

Product Sorter with Vue 3 and Vite
The project should look something like this now

Here are the live preview of the website and the repo for your reference:

Preview CodeDownload

Try clicking on the different terms and watch how the product sorts and the title changes.

Vue makes it easy to design a functional web app without worrying too much of the technical aspects as compared to using vanilla javascript. This is especially crucial if you are a developer that focuses on delivering a finished product as soon as possible.

How have you find this tutorial? What kind of tutorial would you like to see me write about? Do comment here and let me know about it.

We use cookies to improve your experience on our site and to show you relevant advertising.

Read cookie policy

Accept & Close