Ad – 728Γ—90
⚑ Frameworks

Vue.js – Progressive JavaScript Framework

Vue.js is an approachable, performant, and versatile JavaScript framework for building UIs. Unlike React (a library) or Angular (a full framework), Vue is progressive β€” you can sprinkle it into a static page or build a full single-page application. Vue 3's Composition API brings a flexible, logic-reuse-friendly programming model.

⏱️ 24 min read 🎯 Advanced πŸ“… Updated 2026

What Is Vue?

Vue was created by Evan You in 2014 after working on Angular at Google. It picks the best parts of Angular (templates, directives) and React (virtual DOM, component model) while being easier to learn. Vue 3 (released 2020) is the current version, featuring the Composition API, TypeScript support, and improved performance.

Creating a Vue App

JavaScript
// CDN (no build step β€” great for prototyping)
// <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

// HTML: <div id="app">{{ message }}</div>

const { createApp, ref } = Vue;

createApp({
  setup() {
    const message = ref('Hello, Vue!');
    return { message };
  }
}).mount('#app');

// With Vite (recommended for production):
// npm create vue@latest my-app
// cd my-app && npm install && npm run dev

// In a .vue single-file component (SFC):
// <script setup>
// import { ref } from 'vue';
// const message = ref('Hello, Vue!');
// </script>
// <template>
//   <h1>{{ message }}</h1>
// </template>

Template Syntax and Directives

Vue templates use {{ }} for text interpolation and v-* directives for dynamic behaviour:

JavaScript
// In a <script setup> SFC component:

import { ref } from 'vue';

const count = ref(0);
const isVisible = ref(true);
const items = ref(['Apple', 'Banana', 'Cherry']);
const inputText = ref('');
const url = ref('https://vuejs.org');

// Template (shown as a JS comment to fit code block):
// <!-- Text interpolation -->
// <p>Count: {{ count }}</p>

// <!-- v-bind: dynamic attribute (shorthand :) -->
// <a :href="url">Visit Vue.js</a>
// <img :src="imageSrc" :alt="imageAlt" />

// <!-- v-model: two-way data binding -->
// <input v-model="inputText" />
// <p>You typed: {{ inputText }}</p>

// <!-- v-if / v-else-if / v-else: conditional rendering -->
// <p v-if="count > 10">Big number!</p>
// <p v-else-if="count > 0">Positive number</p>
// <p v-else>Zero</p>

// <!-- v-show: toggles CSS display (element stays in DOM) -->
// <div v-show="isVisible">I am shown/hidden via CSS</div>

// <!-- v-for: list rendering -->
// <ul>
//   <li v-for="(item, index) in items" :key="index">
//     {{ index + 1 }}. {{ item }}
//   </li>
// </ul>

// <!-- v-on: event handler (shorthand @) -->
// <button @click="count++">Increment</button>
// <button @click="count = 0">Reset</button>
πŸ’‘
v-if vs v-show

Use v-if when the element is rarely shown β€” it completely removes the element from the DOM, saving render cost. Use v-show for elements toggled frequently β€” it keeps the element in DOM and just toggles display:none, avoiding mount/unmount overhead.

Composition API – ref and reactive

JavaScript
import { ref, reactive, computed, onMounted } from 'vue';

// ref() β€” wraps a primitive in a reactive container
// Access the value with .value in JS, but {{ count }} in template (auto-unwrapped)
const count = ref(0);
console.log(count.value); // 0
count.value++;
console.log(count.value); // 1

// reactive() β€” makes an object deeply reactive (no .value needed)
const user = reactive({
  name: 'Alice',
  age: 30,
  address: { city: 'London' }
});
user.name = 'Bob';             // triggers reactivity
user.address.city = 'Paris';   // deep reactivity

// computed() β€” derived value, auto-updates when deps change
const doubled = computed(() => count.value * 2);
console.log(doubled.value); // 2

const fullName = computed(() => `${user.firstName} ${user.lastName}`);

// Writable computed
const firstName = ref('Alice');
const lastName = ref('Smith');
const fullNameRW = computed({
  get: () => `${firstName.value} ${lastName.value}`,
  set: (val) => {
    [firstName.value, lastName.value] = val.split(' ');
  }
});

Lifecycle Hooks

JavaScript
import { ref, onMounted, onUpdated, onUnmounted, onBeforeMount } from 'vue';

const data = ref(null);

// onBeforeMount β€” before the component is inserted into DOM
onBeforeMount(() => {
  console.log('About to mount');
});

// onMounted β€” component is in DOM (equivalent to useEffect(..., []))
onMounted(async () => {
  console.log('Component mounted');
  const res = await fetch('/api/data');
  data.value = await res.json();
});

// onUpdated β€” after reactive data change caused a re-render
onUpdated(() => {
  console.log('Component updated');
});

// onUnmounted β€” cleanup (timers, subscriptions, event listeners)
let timer;
onMounted(() => { timer = setInterval(() => {}, 1000); });
onUnmounted(() => {
  clearInterval(timer);
  console.log('Cleaned up');
});

Options API vs Composition API

AspectOptions APIComposition API
StyleObject with predefined option keys (data, methods, computed, watch)Free-form functions using imported composables
TypeScriptHarder to typeExcellent TS support
Logic reuseMixins (messy)Composable functions (clean)
Learning curveEasier for beginnersRequires understanding of refs/reactivity
Code organisationBy option type (all data together, all methods together)By feature (all colour logic together)
Recommended forSimple apps, beginnersComplex apps, TypeScript, Vue 3+

Pinia (State) and Nuxt.js (SSR)

JavaScript
// Pinia β€” official Vue state management (replaces Vuex)
// npm install pinia

import { defineStore } from 'pinia';
import { ref, computed } from 'vue';

// Define a store
export const useCartStore = defineStore('cart', () => {
  const items = ref([]);
  const total = computed(() => items.value.reduce((sum, i) => sum + i.price, 0));

  function addItem(product) {
    items.value.push(product);
  }

  function removeItem(id) {
    items.value = items.value.filter(i => i.id !== id);
  }

  return { items, total, addItem, removeItem };
});

// Use in any component:
// import { useCartStore } from './stores/cart';
// const cart = useCartStore();
// cart.addItem({ id: 1, name: 'Book', price: 29.99 });
// console.log(cart.total); // 29.99

// Nuxt.js β€” meta-framework on top of Vue
// Provides: file-based routing, SSR/SSG, API routes, auto-imports
// npx nuxi@latest init my-nuxt-app
ℹ️
Vue vs React: which should you learn?

Both are excellent. React has a larger ecosystem and is more common in enterprise jobs. Vue has a gentler learning curve and is popular in Asia and among indie developers. If you know one, learning the other takes only a few days β€” the concepts are nearly identical.

πŸ‹οΈ Practical Exercise

Build a Vue 3 shopping list app (use CDN or Vite):

  1. Input field + "Add" button. v-model binds the input to a ref.
  2. Items list with v-for. Each item has a checkbox (v-model for checked state) and a delete button.
  3. A computed property counts unchecked items.
  4. A "Clear done" button removes all checked items.
  5. The list is persisted to localStorage using a watch on the items ref.

πŸ”₯ Challenge Exercise

Build a weather dashboard using the Open-Meteo API (https://api.open-meteo.com β€” free, no key). Use Composition API. Create a composable useWeather(lat, lon) that encapsulates the fetch logic and returns { data, loading, error } as refs. The main component has a city selector (hardcode 5 cities with coordinates). When the user selects a city, call the composable and display temperature, wind speed, and a weather code icon. Use Pinia to cache fetched weather data to avoid redundant API calls.

Summary

πŸ“‹ Summary

  • Vue is a progressive framework β€” use as little or as much as you need.
  • Composition API (setup() or <script setup>) is the modern, recommended approach.
  • ref() wraps primitives; reactive() makes objects deeply reactive.
  • computed() creates cached derived values that auto-update.
  • Directives: v-model (two-way), v-bind / : (attribute), v-on / @ (event), v-if/v-show (conditional), v-for (loop).
  • Use onMounted, onUpdated, onUnmounted for lifecycle logic.
  • Pinia is the official state management solution; Nuxt adds SSR/SSG on top of Vue.

Interview Questions

  • What is the difference between ref() and reactive()?
  • What is the difference between v-if and v-show?
  • How does two-way binding with v-model work under the hood?
  • What is a composable in Vue 3 and how does it differ from a mixin?
  • When would you choose Vue over React, or vice versa?

Frequently Asked Questions

Can I use Vue 3 with the Options API instead of Composition API? +

Yes. Both APIs are fully supported in Vue 3 and you can even mix them in the same project (but not the same component). The Options API has a more structured, beginner-friendly feel. The Composition API is recommended for new Vue 3 projects due to better TypeScript support and logic reuse via composables.

What is a Vue composable? +

A composable is a plain JavaScript function (by convention prefixed with use) that uses Vue Composition API functions internally. It encapsulates and reuses stateful logic across multiple components β€” similar to React custom hooks. Example: useWindowSize() returns reactive width and height refs that update on window resize.

What replaced Vuex for state management? +

Pinia is now the official state management library for Vue and has replaced Vuex. It uses the Composition API, has a much simpler API (no mutations, just actions), excellent TypeScript support, and built-in DevTools integration. Vuex 4 still works with Vue 3 but is no longer recommended for new projects.

Ad – 336Γ—280