message
Web Application Development

State Management in Vue 3: Why Pinia Is the Go-To Choice

Blog bannerBlog banner

What is state management?

State management in Vue.js refers to the practice of handling and organising dynamic data known as the "state" that "drives your application's user interface and behaviour." This state includes any data that can change over time, such as user input, fetched API data, or UI toggles.

Why Do We Need State Management?

As Vue applications grow in complexity, managing shared data between components becomes increasingly difficult. Without a proper system, you may end up with prop drilling (passing props through multiple component levels) and event chains (emitting events up and down the component tree), which can make the app harder to understand, maintain, and scale.

To solve this, Vue developers use centralized state management, a technique that stores shared state in a single, global location. This method ensures consistency and predictability across the application by providing a single source of truth for the data.

What is Pinia?

Pinia is the official state management library for Vue 3, designed to be lightweight, intuitive, and fully integrated with Vue’s Composition API. It allows you to define stores that centralize your application’s state and business logic, making it easier to manage, update, and share data across components and pages.

With Pinia, developers can organize their state in a clear and modular way, improving both maintainability and consistency throughout the application.

Why do we use Pinia with Vue 3?

While you can manage global state in Vue 3 using the Composition API (e.g., export const state = reactive({})), this approach becomes limited as your application scales. It lacks features like built-in devtools support, better server-side rendering (SSR) compatibility, and proper encapsulation of logic.

Pinia solves these issues by providing

  1. A centralized and reactive store system
  2. Out-of-the-box SSR support
  3. Better debugging and developer experience through Vue Devtools
  • Key Features of Pinia
    • Reactivity: Built on Vue 3’s reactivity system, Pinia ensures efficient and predictable state updates.
    • TypeScript Support: Out-of-the-box TypeScript support provides type safety and intelligent code completion, even for JavaScript users.
    • Modularity: Encourages breaking your state into multiple stores, promoting maintainability and scalability.

Let’s say you're building an Employee Management System with the following components:

  • EmployeeList.vue: shows a list of employees
  • AddEmployee.vue: a form to add a new employee
  • EmployeeDetails.vue: shows detailed info of the selected employee
  • EmployeeCard.vue: shows the total number of employees

Problem Without State Management

Each component needs to know about the list of employees. When you add a new employee in AddEmployee.Vue, you need to update the list in EmployeeList.vue and the count in EmployeeCard.vue.

Without state management, you'd need to:

  • Emit events from AddEmployee.vue
  • Listen for those events in a parent
  • Pass the updated data down again to EmployeeList and EmployeeCard via props

Let's create a real-life example of an Employee Management System to demonstrate how Pinia simplifies state handling in a Vue 3 application

What We'll Build

In this tutorial, you will implement state management in an employee management system built with Vue 3. You will start with a pre-built application that allows you to manage employee records, including adding, updating &  organizing employee details.

  • Load the employee data from a central state store
  • Add new employee records
  • Display the list of employees
  • View detailed information for a specific employee
  • Mark an employee as a "star" performer
  • Display a separate list of starred employees
  • Update individual employee details, such as role or department
  • Remove employees from the list

Prerequisites

A few requirements must be met before starting this exercise.

Basic Knowledge of Vue 3

You should be familiar with Vue 3 syntax, components, and reactive state.

Node.js and npm are installed

Ensure you have the recommended Node.js (v22.17.0) and npm installed on your system.

Basic Understanding of JavaScript

Familiarity with modern JavaScript features (like let/const, arrow functions, etc.) 

Vue 3 + Pinia: Create an Employee Management System Step by Step

Set Up the Project

Code

  ztlab120@Zignutss-Mac-mini blog % npm create vue@latest
  ┌  Vue.js - The Progressive JavaScript Framework
  │
  ◇  Project name (target directory):
  │  employee-management-system
  │
  ◆  Select features to include in your project: (↑/↓ to navigate, space to
  select, a to toggle all, enter to confirm)
  │  ◻ TypeScript
  │  ◻ JSX Support
  │  ◻ Router (SPA development)
  │  ◼ Pinia (state management)
  │  ◻ Vitest (unit testing)
  │  ◻ End-to-End Testing
  │  ◻ ESLint (error prevention)
  │  ◻ Prettier (code formatting)
  └               
      

Install the dependencies & run the dev server.

Code

  cd employee-management-system

  // install dependencies 
  npm install
  
  // Run dev server
  npm run dev                       
      

Index.html: Replace the code in index.html with the following:

Code

  <!DOCTYPE html>
  <html lang="">
    <head>
      <meta charset="UTF-8">
      <link rel="icon" href="/favicon.ico">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Employee Management System</title>
      <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/gh/hardikzignuts/vue-pinia-demo-app@main/main.css"
      />
    </head>
    <body>
      <div id="app"></div>
      <script type="module" src="/src/main.js"></script>
    </body>
  </html>                      
      

In main.js:  Replace the code in src/main.js with the following:

Code

  import { createApp } from 'vue'
  import { createPinia } from 'pinia'
  import App from './App.vue'
  
  const app = createApp(App)
  
  app.use(createPinia())
  
  app.mount('#app')                        
      
Hire Now!

Hire Vue.js Developers Today!

Ready to bring your app vision to life? Start your journey with Zignuts expert iOS developers.

**Hire now**Hire Now**Hire Now**Hire now**Hire now

Create the Pinia Store

Create an employee.js file inside the src/stores folder and add the following code:

Code

  import { ref, computed } from "vue";
  import { defineStore } from "pinia";
  
  export const useEmployeeStore = defineStore("employees", () => {
    // State
    const employees = ref([
      {
        id: 1,
        firstName: "John",
        lastName: "Doe",
        email: "john.doe@company.com",
        department: "Engineering",
        position: "Senior Developer",
        salary: 85000,
        status: "active",
        hireDate: new Date("2020-03-15"),
        phone: "9878675646",
        isSelected: false
      },
    ]);
  
    const editingEmployeeId = ref(null);
    const showModal = ref(false);
    const isAddEmployeeModal = ref(false)
    const showSelectedEmployeeModal = ref(false)
    const showSelectedEmployeeDetailModal = ref(false)
  
    // Actions
    const openAddEmployeeModal = () => {
      isAddEmployeeModal.value = true
    }
  
    // Function for add new employee
    const addEmployee = (employeeData) => {
      const newEmployee = {
        ...employeeData,
        id: Date.now(),
        hireDate: new Date(),
        status: "active",
        isSelected: false
      };
      employees.value.push(newEmployee);
    };
  
    // Function for Update employee details
    const updateEmployee = (id, updates) => {
      const index = employees.value.findIndex((emp) => emp.id === id);
      if (index !== -1) {
        employees.value[index] = { ...employees.value[index], ...updates };
      }
    };
  
    // Function for delete employee
    const deleteEmployee = (id) => {
      const index = employees.value.findIndex((emp) => emp.id === id);
      if (index !== -1) {
        employees.value.splice(index, 1);
      }
    };
  
    // Function for open employee edit modal
    const openEditModal = (id) => {
      editingEmployeeId.value = id
      showModal.value = true;
    };
  
    // Function for close employee edit model
    const closeModal = () => {
      showModal.value = false;
      editingEmployeeId.value = null;
    };
  
    // Function for close selected employee model
    const closeSelectedEmployeeModal = () => {
      showSelectedEmployeeModal.value = false
    }
  
    // Function for close selected employee detail model
    const closeSelectedEmployeeDetailModal = () => {
      showSelectedEmployeeDetailModal.value = false
    }
  
    // Function for format currency
    const formatCurrency = (amount) => {
      return new Intl.NumberFormat("en-IN", {
        style: "currency",
        currency: "INR",
      }).format(amount);
    };
  
    // Function for format date
    const formatDate = (date) => {
      return new Intl.DateTimeFormat("en-IN", {
        year: "numeric",
        month: "short",
        day: "numeric",
      }).format(date);
    };
  
    // Function for calculate number of year employee service 
    const getYearsOfService = (hireDate) => {
      const years = (new Date() - hireDate) / (1000 * 60 * 60 * 24 * 365);
      return Math.floor(years);
    };
  
    // Function for toggle selected employee
    const toggleSelectedEmployee = (id) => {
      const employee = employees.value.find((item) => item.id === id)
      employee.isSelected = !employee.isSelected
    }
  
    return { employees, editingEmployeeId, showModal, isAddEmployeeModal, showSelectedEmployeeModal, showSelectedEmployeeDetailModal, openAddEmployeeModal, addEmployee, updateEmployee, deleteEmployee, openEditModal, closeModal, formatCurrency, formatDate, getYearsOfService, toggleSelectedEmployee, closeSelectedEmployeeModal, closeSelectedEmployeeDetailModal };
  });                                
      

Create Components

​​Create a directory named employee inside the src/components folder (src/components/employee) and add the following components:

1. EmployeeList.vue: Displays a grid of all employees. Allows viewing details, editing, and removing employees.

Code

  <script setup>
    import { useEmployeeStore } from "@/stores/employee";
    import AddEditEmployee from "./AddEditEmployee.vue";
    import Employee from "./Employee.vue";
    import { ref } from "vue";
    import EmployeeDetailView from "./EmployeeDetailView.vue"
    
    const employeeStore = useEmployeeStore();
    const activeDropdownId = ref(null)
    const employeeDetailViewId = ref(null)
    const isDetailModalShow = ref(false)
    
    const setActiveDropdownId = (id) => {
      activeDropdownId.value = id === activeDropdownId.value ? null : id
    }
    
    const openDetailModal = (id) => {
      isDetailModalShow.value = true
      employeeStore.showSelectedEmployeeDetailModal = true
      employeeDetailViewId.value = id
    }
  </script>
    
  <template>
    <div class="content">
     <!-- EMPLOYEE LIST START -->
      <div v-if="employeeStore.employees.length > 0" class="employee-grid">
        <Employee v-for="employee in employeeStore.employees" :key="employee.id" :employee="employee"
          :active-dropdown-id="activeDropdownId" @set-active-dropdown="setActiveDropdownId"
          @open-employee-detail-view="openDetailModal" />
        <EmployeeDetailView v-if="isDetailModalShow" :id="employeeDetailViewId"
          @close="employeeDetailViewId = null, isDetailModalShow = false" />
      </div>
      <!-- EMPLOYEE LIST END -->
      <!-- SHOW WHEN NO EMPLOYEE FOUND -->
      <div v-else class="empty-state">
        <h3>No employees found</h3>
        <p>Try adjusting your search criteria or add new employees.</p>
      </div>
      <!-- Add/Edit employee Modal -->
      <AddEditEmployee v-if="employeeStore.showModal || employeeStore.isAddEmployeeModal" />
    </div>
  </template>                         
      

2. Employee.vue: Displays a single employee's card with their avatar, name, position, and status. Allows opening a detail view, editing, or removing the employee, and marking them as a “star” (selected) directly from the card.

Code

  <script setup>
    import { useEmployeeStore } from "@/stores/employee";
    
    const props = defineProps({
        employee: Object,
        activeDropdownId: Number,
    });
    
    const emit = defineEmits(["set-active-dropdown", "open-employee-detail-view"]);
    const employeeStore = useEmployeeStore();
    
    // Function for create employee avatar image base on employee firstName and lastName
    const employeeAvatar = (firstName, lastName) => {
        return (firstName[0] + lastName[0]).toUpperCase();
    };
    
    // Function for toggle action button dropdown
    const toggleDropdown = () => {
        emit("set-active-dropdown", props.employee.id);
    };
    
    // Function for open employee detail view modal
    const openDetailView = () => {
        emit('open-employee-detail-view', props.employee.id)
        if (props.activeDropdownId) {
            emit("set-active-dropdown", null);
        }
    };
    
    // Function to open selected employee edit modal
    const handelEditEmployee = () => {
        employeeStore.openEditModal(props.employee.id)
        emit("set-active-dropdown", null);
    }
  </script>
    
  <template>
      <div class="employee-card" @click="openDetailView">
          <div class="employee-header">
              <div class="avatar-name">
                  <div class="employee-avatar">
                      {{ employeeAvatar(employee.firstName, employee.lastName) }}
                  </div>
                  <div class="employee-info">
                      <h3>{{ employee.firstName }} {{ employee.lastName }}</h3>
                      <p>{{ employee.position }}</p>
                  </div>
              </div>
              <span :class="['status-badge', 'status-' + employee.status]">
                  {{ employee.status }}
              </span>
              <div :id="employee.id" class="more-actions-container">
                  <button @click.stop="toggleDropdown" class="more-btn">
                      ...
                  </button>
  
                  <div @click.stop v-if="activeDropdownId === employee.id" class="dropdown-menu">
                      <button @click="handelEditEmployee" class="dropdown-item">
                          Edit
                      </button>
                      <button @click="employeeStore.deleteEmployee(employee.id)" class="dropdown-item delete">
                          Delete
                      </button>
                  </div>
              </div>
          </div>
  
          <div class="star-icon" v-if="employee.status !== 'inactive'">
              <span @click.stop="employeeStore.toggleSelectedEmployee(employee.id)"><svg
                      xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                      :fill="employee.isSelected ? '#e7e761' : '#808080'" stroke="currentColor" stroke-width="2"
                      stroke-linecap="round" stroke-linejoin="round"
                      class="icon icon-tabler icons-tabler-outline icon-tabler-star"
                      :style="{ color: employee.isSelected ? '#e7e761' : '#808080' }">
                      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
                      <path
                          d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" />
                  </svg>
              </span>
          </div>
      </div>
  </template>                        
      

3. AddEditEmployee.vue: Displays a modal form for adding or editing an employee's details. 

Code

  <script setup>
    import { onMounted, reactive, computed, watch } from "vue";
    import { useEmployeeStore } from "@/stores/employee";
    
    const employeeStore = useEmployeeStore();
    
    // Detect mode
    const isEditMode = computed(() => employeeStore.showModal);
    const isAddMode = computed(() => employeeStore.isAddEmployeeModal);
    
    // Shared form state
    const employeeForm = reactive({
        firstName: "",
        lastName: "",
        email: "",
        department: "Engineering",
        position: "",
        salary: 0,
        status: "active",
        phone: "",
    });
    
    // Reset form for Add
    const resetForm = () => {
        Object.assign(employeeForm, {
            firstName: "",
            lastName: "",
            email: "",
            department: "Engineering",
            position: "",
            salary: 0,
            status: "active",
            phone: "",
        });
    };
    
    // Add employee
    const handleAddEmployee = () => {
        if (employeeForm.firstName && employeeForm.lastName && employeeForm.email) {
            employeeStore.addEmployee({ ...employeeForm });
            resetForm();
            employeeStore.isAddEmployeeModal = false;
        }
    };
    
    // Update employee
    const handleUpdateEmployee = () => {
        if (employeeForm && employeeStore.editingEmployeeId) {
            // If the updated status is inactive, we force isSelected to false
            if (employeeForm.status === 'inactive') {
                employeeForm.isSelected = false;
            }
            employeeStore.updateEmployee(employeeStore.editingEmployeeId, { ...employeeForm });
            employeeStore.closeModal();
        }
    };
    
    // Close modal handler
    const handleClose = () => {
        resetForm();
        employeeStore.closeModal();
        employeeStore.isAddEmployeeModal = false;
    };
    
    onMounted(() => {
        const ID = employeeStore.editingEmployeeId;
        const emp = employeeStore.employees.find((item) => item.id === ID);
        if (emp) Object.assign(employeeForm, { ...emp });
    });
  </script>
  <template>
    <div v-if="isEditMode || isAddMode" class="modal" @click.self="handleClose">
      <div class="modal-content">
        <div class="modal-header">
          <h2 class="modal-title">{{ isEditMode ? "Edit" : "Add" }} Employee</h2>
          <button @click="handleClose" class="close-btn">×</button>
        </div>

        <div class="form-group">
          <label class="form-label">First Name</label>
          <input v-model="employeeForm.firstName" class="form-input" />
        </div>

        <div class="form-group">
          <label class="form-label">Last Name</label>
          <input v-model="employeeForm.lastName" class="form-input" />
        </div>

        <div class="form-group">
          <label class="form-label">Email</label>
          <input v-model="employeeForm.email" type="email" class="form-input" />
        </div>

        <div class="form-group">
          <label class="form-label">Department</label>
          <select v-model="employeeForm.department" class="form-select">
            <option value="Engineering">Engineering</option>
            <option value="Marketing">Marketing</option>
            <option value="Sales">Sales</option>
            <option value="HR">HR</option>
            <option value="Finance">Finance</option>
          </select>
        </div>

        <div class="form-group">
          <label class="form-label">Position</label>
          <input v-model="employeeForm.position" class="form-input" />
        </div>

        <div class="form-group">
          <label class="form-label">Salary</label>
          <input
            v-model.number="employeeForm.salary"
            type="number"
            class="form-input"
          />
        </div>

        <div class="form-group" v-if="isEditMode">
          <label class="form-label">Status</label>
          <select v-model="employeeForm.status" class="form-select">
            <option value="active">Active</option>
            <option value="vacation">On Vacation</option>
            <option value="inactive">Inactive</option>
          </select>
        </div>

        <div class="form-group">
          <label class="form-label">Phone</label>
          <input v-model="employeeForm.phone" class="form-input" />
        </div>

        <div class="add-edit-modal-footer">
          <button
            @click="isEditMode ? handleUpdateEmployee() : handleAddEmployee()"
            class="btn btn-primary"
          >
            {{ isEditMode ? "Update" : "Add" }} Employee
          </button>
          <button @click="handleClose" class="btn btn-secondary">Cancel</button>
        </div>
      </div>
    </div>
  </template>

4. EmployeeCard.vue: Displays the main header for the Employee Management System, including the title and a selected employee indicator. Shows the count of selected employees and opens the selected employee modal on click.

Code

  <script setup>
    import { useEmployeeStore } from "@/stores/employee";
    import { computed } from "vue";
    import SelectedEmployee from './SelectedEmployeeList.vue'
    
    const employeeStore = useEmployeeStore();
    
    const selectedEmployeeCount = computed(() =>
      employeeStore.employees.filter(item => item.isSelected).length
    )
  </script>
  <template>
    <div class="header">
      <div class="title">
        <h1>Employee Management System</h1>
          <button @click="employeeStore.openAddEmployeeModal()" class="btn btn-secondary btn-add-employee">
            Add New Employee
          </button>
        <div class="selected-emp" @click="employeeStore.showSelectedEmployeeModal = true">
          <span>Selected Employee</span>
          <span>⭐️</span>
          <span class="selected-emp-count"> {{ selectedEmployeeCount }}</span>
        </div>
      </div>
      <SelectedEmployee />
    </div>
  </template>                       
      

5. SelectedEmployeeList.vue:  Displays a modal with all currently selected employees. Allows users to view brief details, remove individuals from the selection, clear all selections at once, and view full details of a selected employee in a separate modal.

Code

  <script setup>
    import { computed, ref } from 'vue'
    import { useEmployeeStore } from "@/stores/employee";
    import EmployeeDetailView from './EmployeeDetailView.vue';
    
    const employeeStore = useEmployeeStore();
    const employeeDetailViewId = ref(null)
    const isDetailModalShow = ref(false)
    // Get selected employees list
    const selectedEmployees = computed(() =>
      employeeStore.employees.filter(employee => employee.isSelected)
    )
    
    // Function for remove all employee from selected employee list
    const clearAllSelections = () => {
      employeeStore.employees.forEach(employee => {
        employee.isSelected = false
      })
    }
    
    // Function for open selected employee detail modal 
    const getSelectedEmployeeDetail = (id) => {
      isDetailModalShow.value = true
      employeeDetailViewId.value = id
      employeeStore.showSelectedEmployeeDetailModal = true
    }
    
    const closeDetailModal = () => {
      isDetailModalShow.value = false
      employeeDetailViewId.value = null
    }
  </script>
  <template>
    <div v-if="employeeStore.showSelectedEmployeeModal" class="selected-employee-modal"
      @click.self="employeeStore.closeSelectedEmployeeModal">
      <div class="emp-modal-content">
        <div class="emp-modal-header">
          <h2 class="emp-modal-title">Selected Employees</h2>
          <button @click="employeeStore.closeSelectedEmployeeModal" class="close-btn">
            ×
          </button>
        </div>
  
        <div class="emp-modal-body">
          <!-- Selected count -->
          <div class="selected-count">
            <span class="count-badge">{{ selectedEmployees.length }}</span>
            employee{{ selectedEmployees.length !== 1 ? 's' : '' }} selected
          </div>
  
          <!-- Selected employees list -->
          <div v-if="selectedEmployees.length > 0" class="employee-list">
            <div v-for="employee in selectedEmployees" :key="employee.id" class="employee-item"
              @click="getSelectedEmployeeDetail(employee.id)">
              <div class="employee-avatar">
                <div class="avatar-placeholder">
                  {{ employee.firstName?.charAt(0)?.toUpperCase() }}
                </div>
              </div>
  
              <div class="employee-info">
                <h3 class="employee-name">{{ employee.firstName }} {{ employee.lastName }}</h3>
                <p>
                  <span class="employee-position">{{ employee.position }}</span>
                  <span v-if="employee.department" class="employee-department">
                    • {{ employee.department }}
                  </span>
                </p>
                <p v-if="employee.email" class="employee-email">
                  {{ employee.email }}
                </p>
              </div>
  
              <button @click.stop="employeeStore.toggleSelectedEmployee(employee.id)" class="remove-btn"
                title="Remove from selection">
                ✕
              </button>
            </div>
          </div>
  
          <!-- Empty state -->
          <div v-else class="empty-state">
            <p>No employees selected</p>
          </div>
        </div>
  
        <div class="modal-footer">
          <button @click="clearAllSelections" class="btn btn-outline">
            Clear All
          </button>
          <button @click="employeeStore.closeSelectedEmployeeModal" class="btn btn-primary">
            Close
          </button>
        </div>
      </div>
    </div>
    <EmployeeDetailView v-if="isDetailModalShow" :id="employeeDetailViewId" @close="closeDetailModal" />
  </template>                       
      

6. EmployeeDetailView.vue: Displays a modal with detailed information about a selected employee. Shows their personal details, department, salary, phone, and years of service. Allows the user to edit or delete the employee's information

Code


          <script setup>
          import { onMounted, ref } from "vue";
          import { useEmployeeStore } from "@/stores/employee";
          import AddEditEmployee from "./AddEditEmployee.vue";
          
          const employeeStore = useEmployeeStore();
          const employee = ref();
          const props = defineProps({
              id: Number,
          });
          
          const emit = defineEmits("close");
          
          const handleEditEmployee = () => {
              closeModal();
              employeeStore.openEditModal(props.id);
          };
          
          const handleDeleteEmployee = () => {
              employeeStore.deleteEmployee(props.id);
              closeModal();
          };
          
          const closeModal = () => {
              employeeStore.closeSelectedEmployeeDetailModal();
              emit("close");
          };
          onMounted(() => {
              employee.value = employeeStore.employees.find((item) => item.id === props.id);
          });
          </script>
          
          <template>
              <div class="selected-employee-modal" @click.self="closeModal">
                  <div class="emp-modal-content">
                      <div class="emp-modal-header">
                          <h2 class="emp-modal-title">Employee Details</h2>
                          <button @click="closeModal" class="close-btn">×</button>
                      </div>
          
                      <div class="emp-modal-body" v-if="employee">
                          <!-- Selected employees list -->
                          <div class="employee-item">
                              <div class="employee-avatar">
                                  <div class="avatar-placeholder">
                                      {{ employee.firstName?.charAt(0)?.toUpperCase() }}
                                  </div>
                              </div>
          
                              <div class="employee-info">
                                  <h3 class="employee-name">
                                      {{ employee.firstName }} {{ employee.lastName }}
                                  </h3>
                                  <p>
                                      <span class="employee-position">{{ employee.position }}</span>
                                      <span v-if="employee.department" class="employee-department">
                                          • {{ employee.department }}
                                      </span>
                                  </p>
                                  <p v-if="employee.email" class="employee-email">
                                      {{ employee.email }}
                                  </p>
                              </div>
                          </div>
          
                          <div class="employee-details">
                              <div class="detail-row">
                                  <span class="detail-label">Email:</span>
                                  <span class="detail-value">{{ employee.email }}</span>
                              </div>
                              <div class="detail-row">
                                  <span class="detail-label">Department:</span>
                                  <span class="detail-value">{{ employee.department }}</span>
                              </div>
                              <div class="detail-row">
                                  <span class="detail-label">Salary:</span>
                                  <span class="detail-value">{{
                                      employeeStore.formatCurrency(employee.salary)
                                  }}</span>
                              </div>
                              <div class="detail-row">
                                  <span class="detail-label">Phone:</span>
                                  <span class="detail-value">{{ employee.phone }}</span>
                              </div>
                              <div class="detail-row">
                                  <span class="detail-label">Hired:</span>
                                  <span class="detail-value">{{ employeeStore.formatDate(employee.hireDate) }} ({{
                                      employeeStore.getYearsOfService(employee.hireDate)
                                  }}
                                      years)</span>
                              </div>
                          </div>
                      </div>
          
                      <div class="modal-footer">
                          <button @click="handleEditEmployee" class="action-btn btn-primary">
                              Edit
                          </button>
                          <button @click="handleDeleteEmployee" class="action-btn btn-danger">
                              Delete
                          </button>
                      </div>
                  </div>
                  <AddEditEmployee v-if="employeeStore.showModal "/> 
              </div>
          </template>                                   
      

7. EmployeesOverview.vue

Code

  <script setup>
  import EmployeeCard from "./EmployeeCard.vue";
  import EmployeeList from "./EmployeeList.vue"
  </script>
  
  <template>
    <div>
      <EmployeeCard />
      <EmployeeList />
    </div>
  </template>                          
      

App.vue: Replace the code in src/App.vue with the following:

Code

  <script setup>
  import EmployeesOverview from "./components/employee/EmployeesOverview.vue";
  </script>
  
  <template>
    <div>
      <EmployeesOverview />
    </div>
  </template>                         
      
Hire Now!

Hire Vue.js Developers Today!

Ready to bring your app vision to life? Start your journey with Zignuts expert iOS developers.

**Hire now**Hire Now**Hire Now**Hire now**Hire now

Conclusion

Pinia has emerged as the official and modern solution for state management in Vue 3 applications, and for good reason. Its seamless integration with the Composition API, strong TypeScript support, simplified API, and modular structure make it a natural fit for both small and large-scale projects.

Ready to build powerful Vue 3 applications with clean state management? Whether you need help with a new project or want to scale your existing app, our expert Vue developers are here to help.Contact us today to discuss your requirements and bring your vision to life.

card user img
Twitter iconLinked icon

Passionate developer with expertise in building scalable web applications and solving complex problems. Loves exploring new technologies and sharing coding insights.

card user img
Twitter iconLinked icon

Passionate developer with expertise in building scalable web applications and solving complex problems. Loves exploring new technologies and sharing coding insights.

Book a FREE Consultation

No strings attached, just valuable insights for your project

Valid number
Please complete the reCAPTCHA verification.
Claim My Spot!
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
download ready
Thank You
Your submission has been received.
We will be in touch and contact you soon!

Our Latest Blogs

View All Blogs