Top Interview Questions
Vue.js (commonly called “Vue”) is an open-source JavaScript framework used for building user interfaces (UIs) and single-page applications (SPAs). Created by Evan You in 2014, Vue has grown into one of the most popular frontend frameworks alongside React and Angular. It is known for its simplicity, flexibility, and performance.
At its core, Vue.js focuses on the view layer of an application—the part users interact with—while also offering tools and libraries to handle complex application logic when needed.
One of Vue’s standout features is its reactivity system. When data changes, the UI automatically updates without manual DOM manipulation. This is based on the concept of a reactive data model, where Vue tracks dependencies and updates only the necessary parts of the interface.
For example:
const app = Vue.createApp({
data() {
return {
message: "Hello Vue!"
}
}
})
If message changes, Vue updates the UI instantly.
Vue applications are built using components, which are reusable and self-contained pieces of code. Each component typically includes:
Template (HTML structure)
Script (logic)
Style (CSS)
This modular approach makes applications easier to maintain and scale.
Vue uses a declarative syntax, meaning you describe what the UI should look like based on the data, and Vue handles how to update it.
Example:
<div>{{ message }}</div>
Vue provides special attributes called directives that extend HTML functionality. Common ones include:
v-bind → Bind attributes
v-model → Two-way data binding
v-if → Conditional rendering
v-for → Loop through data
Example:
<input v-model="message">
Like React, Vue uses a Virtual DOM, which is a lightweight representation of the real DOM. Changes are computed efficiently and applied only where necessary, improving performance.
Vue is often described as a progressive framework, meaning you can:
Use it for a small part of a webpage, or
Build full-scale applications
It integrates easily with existing projects, unlike some frameworks that require a full rewrite.
Vue is not just a framework—it comes with a rich ecosystem of supporting tools:
Handles navigation between different views/pages in a single-page application.
State management libraries for managing shared data across components. Pinia is now the modern recommendation.
Tools for setting up and building Vue projects quickly. Vite is especially popular for its speed.
Vue has evolved over time, with major versions including:
Vue 2: Widely used, stable, and beginner-friendly
Vue 3: Modern version with improved performance and features like:
Composition API
Better TypeScript support
Smaller bundle size
Vue 3 is now the recommended version for new projects.
Vue offers two ways to write components:
export default {
data() {
return { count: 0 }
},
methods: {
increment() {
this.count++
}
}
}
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
const increment = () => count.value++
return { count, increment }
}
}
The Composition API is more flexible and better suited for large applications.
Vue is easy to learn compared to other frameworks. Its syntax is simple, and developers can start with basic HTML, CSS, and JavaScript knowledge.
Vue has a small bundle size, which helps in faster load times.
You can use Vue for:
Small widgets
Medium applications
Large enterprise-level systems
Vue has a large and active community, with plenty of tutorials, plugins, and support.
Vue’s official documentation is widely regarded as one of the best in the frontend ecosystem.
Although growing, Vue’s ecosystem is still smaller than React’s in terms of third-party libraries.
Vue allows multiple ways to do the same thing, which can lead to inconsistency in large teams.
In some regions, demand for Vue developers may be lower compared to React or Angular.
| Feature | Vue.js | React | Angular |
|---|---|---|---|
| Learning Curve | Easy | Medium | Hard |
| Flexibility | High | High | Low |
| Size | Small | Medium | Large |
| Backing | Independent | Meta |
Vue is best for simplicity and rapid development
React is best for flexibility and ecosystem
Angular is best for enterprise-level structure
Vue is used in a wide range of applications:
Apps that load once and dynamically update content without refreshing.
Admin panels and analytics dashboards benefit from Vue’s reactive UI.
Vue is often used to build fast, interactive shopping experiences.
Vue supports building apps that work offline and behave like native apps.
Many well-known companies use Vue in production:
Alibaba
Xiaomi
GitLab
Adobe
Here’s a minimal Vue example:
<div id="app">
<p>{{ message }}</p>
<button @click="reverseMessage">Reverse</button>
</div>
<script>
Vue.createApp({
data() {
return {
message: "Hello Vue!"
}
},
methods: {
reverseMessage() {
this.message = this.message.split('').reverse().join('')
}
}
}).mount('#app')
</script>
This app displays a message and reverses it when the button is clicked.
You might choose Vue if you want:
A simple and clean framework
Fast development with minimal setup
Flexibility to scale your application
A balance between power and ease of use
Vue is especially ideal for beginners and small teams, but it is also powerful enough for large-scale applications.
Vue.js is a modern, progressive JavaScript framework that strikes a balance between simplicity and capability. With features like reactive data binding, component-based architecture, and a strong ecosystem, it enables developers to build fast and maintainable web applications.
Whether you’re just starting out in frontend development or building a complex application, Vue provides a smooth and efficient development experience.
Answer:
Vue.js is a progressive JavaScript framework used for building user interfaces, especially single-page applications (SPAs).
It focuses on the view layer only
Easy to integrate with other libraries or existing projects
Uses a component-based architecture
Answer:
Some important features:
Reactive Data Binding – UI updates automatically when data changes
Component-Based Architecture
Virtual DOM
Directives (v-if, v-for, etc.)
Computed Properties & Watchers
Lightweight & easy to learn
Answer:
A Vue instance is the root object that controls a Vue app.
Example:
const app = Vue.createApp({
data() {
return {
message: "Hello Vue!"
}
}
});
It connects data + template + methods
Every Vue app starts with creating an instance
Answer:
Data binding means synchronizing data between the model and the view.
Types:
One-way binding → {{ message }}
Two-way binding → v-model
Example:
<input v-model="name">
<p>{{ name }}</p>
Answer:
Directives are special attributes with v- prefix that control DOM behavior.
Common directives:
v-bind → bind attributes
v-model → two-way binding
v-if → conditional rendering
v-for → looping
v-on → event handling
Example:
<p v-if="isVisible">Hello</p>
Answer:
| Feature | v-if | v-show |
|---|---|---|
| Rendering | Adds/removes element | Toggles visibility |
| Performance | Slower (DOM creation) | Faster |
| Use case | Conditional rarely changes | Frequent toggling |
Answer:
A component is a reusable piece of UI with its own logic and template.
Example:
app.component('my-component', {
template: `<h1>Hello Component</h1>`
});
Helps in code reusability
Makes app modular
Answer:
| Props | Data |
|---|---|
| Passed from parent | Local state |
| Read-only | Mutable |
| Used for communication | Used for internal logic |
Answer:
Computed properties are cached values that depend on reactive data.
Example:
computed: {
fullName() {
return this.firstName + " " + this.lastName;
}
}
Only recalculates when dependencies change
Better performance than methods
Answer:
Watchers observe changes and execute code.
Example:
watch: {
count(newVal, oldVal) {
console.log("Changed:", newVal);
}
}
Used for async operations or API calls
Answer:
Vue instance goes through several stages:
created → data initialized
mounted → DOM ready
updated → data changes
unmounted → destroyed
Example:
mounted() {
console.log("Component mounted");
}
Answer:
Vue CLI is a tool to create and manage Vue projects.
Command:
npm install -g @vue/cli
vue create my-project
Answer:
Vue Router is used for navigation between pages in SPA.
Features:
Dynamic routing
Nested routes
Route guards
Answer:
Vuex is a state management library for Vue apps.
Used when:
Many components share data
Core concepts:
State
Mutations
Actions
Getters
Answer:
Used to bind HTML attributes dynamically.
Example:
<img v-bind:src="imageURL">
Shortcut:
<img :src="imageURL">
Answer:
Creates two-way binding between input and data.
Example:
<input v-model="username">
Answer:
Using v-on directive.
Example:
<button v-on:click="handleClick">Click</button>
Shortcut:
<button @click="handleClick">
Answer:
A .vue file that contains:
<template></template>
<script></script>
<style></style>
Benefits:
Better organization
Scoped styles
Answer:
A lightweight copy of real DOM.
Vue updates only changed parts
Improves performance
Answer:
Easy to learn
Lightweight
Flexible
Great documentation
Faster development
Answer:
| Feature | Methods | Computed |
|---|---|---|
| Execution | Runs every time called | Cached |
| Performance | Less efficient | More efficient |
| Use case | Actions/events | Derived values |
Example:
data() {
return {
firstName: "John",
lastName: "Doe"
}
},
methods: {
fullNameMethod() {
return this.firstName + " " + this.lastName;
}
},
computed: {
fullNameComputed() {
return this.firstName + " " + this.lastName;
}
}
π Key Point:
Computed is preferred when the result depends on reactive data.
Answer:
| Computed | Watch |
|---|---|
| Returns value | Performs side effects |
| Cached | Not cached |
| Used in templates | Used for async or complex logic |
Example (watch):
watch: {
search(query) {
this.fetchResults(query);
}
}
π Use watch when:
Calling APIs
Performing async tasks
Answer:
Lifecycle hooks allow you to run code at specific stages.
created()
Data initialized
API calls can be made
mounted()
DOM available
Good for DOM manipulation
updated()
Runs after data change
unmounted()
Cleanup (timers, listeners)
Example:
mounted() {
console.log("DOM is ready");
}
Answer:
| created() | mounted() |
|---|---|
| No DOM access | DOM available |
| Faster | Slightly slower |
| Used for API calls | Used for DOM manipulation |
Answer:
The key attribute helps Vue identify elements uniquely when rendering lists.
Example:
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
π Prevents bugs and improves performance.
Answer:
Showing/hiding elements based on conditions.
Directives:
v-if
v-else
v-show
Example:
<p v-if="isLoggedIn">Welcome</p>
<p v-else>Please login</p>
Answer:
Rendering multiple elements using v-for.
Example:
<ul>
<li v-for="user in users" :key="user.id">
{{ user.name }}
</li>
</ul>
π Can loop through:
Arrays
Objects
Numbers
Answer:
Modifiers simplify event handling.
Examples:
<form @submit.prevent="submitForm">
<button @click.stop="handleClick">
Common modifiers:
.prevent → prevent default
.stop → stop propagation
.once → run once
Answer:
Using v-model with different inputs.
Examples:
<input v-model="text">
<input type="checkbox" v-model="checked">
<select v-model="selected">
π Vue automatically handles value syncing.
Answer:
Switching components dynamically.
Example:
<component :is="currentComponent"></component>
data() {
return {
currentComponent: "HomeComponent"
}
}
Answer:
Slots allow content distribution in components.
<slot></slot>
<MyComponent>
<p>Hello Slot</p>
</MyComponent>
Answer:
Multiple slots with names.
<slot name="header"></slot>
<slot name="footer"></slot>
Usage:
<template v-slot:header>
Header Content
</template>
Answer:
Ensures props are passed correctly.
props: {
age: {
type: Number,
required: true,
default: 18
}
}
Answer:
Used to send data from child to parent.
this.$emit('update', data);
Parent:
<Child @update="handleUpdate" />
Answer:
Parent → Child → via props
Child → Parent → via emit
Answer:
Used to share data across deeply nested components.
provide() {
return {
message: "Hello"
}
}
inject: ['message']
Answer:
Reusable logic across components.
const myMixin = {
created() {
console.log("Mixin called");
}
}
Answer:
A modern way to write Vue logic (Vue 3).
import { ref } from 'vue';
setup() {
const count = ref(0);
return { count };
}
π Better for:
Large apps
Code reuse
Answer:
Creates reactive variables.
const count = ref(0);
Access:
count.value
Answer:
Used for objects.
import { reactive } from 'vue';
const state = reactive({
name: "John"
});
A web app that loads a single HTML page and updates dynamically without reload.
| Vue 2 | Vue 3 |
|---|---|
| Options API | Composition API |
| Slower | Faster |
| Limited TS support | Better TypeScript |
Loading components only when needed.
Delaying function execution (e.g., search input).
Interviewers often ask:
π “Explain with example”
π “Where did you use this?”
So prepare:
Todo app
API fetch example
Form validation
Be ready to write small code snippets
Understand basic JavaScript concepts
Practice mini projects (Todo app, Counter app)
Know difference between:
methods vs computed
props vs state
v-if vs v-show
Vue 3 introduced major improvements:
Vue 2: Options API (data, methods, computed)
Vue 3: Composition API (setup())
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return { count }
}
}
π Benefits:
Better logic reuse
Cleaner large components
TypeScript friendly
Vue 2: Object.defineProperty
Vue 3: Proxy
π Advantages:
Detects property addition/deletion
Better performance
No need for Vue.set()
Faster rendering using Virtual DOM optimizations
Tree-shaking support → smaller bundles
Fragments (multiple root elements)
Teleport
Suspense
export default {
data() {
return { count: 0 }
},
methods: {
increment() {
this.count++
}
}
}
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
const increment = () => count.value++
return { count, increment }
}
}
| Feature | Options API | Composition API |
|---|---|---|
| Code organization | Feature-based | Logic-based |
| Reusability | Mixins | Composables |
| TypeScript support | Limited | Excellent |
π For 4+ years: Composition API is preferred
Reactivity means Vue automatically updates the UI when data changes.
ref() → for primitives
reactive() → for objects
const count = ref(0)
const state = reactive({ name: 'John' })
Vue uses Proxy to track:
getters → dependency tracking
setters → trigger updates
| Feature | ref() | reactive() |
|---|---|---|
| Data type | Primitive & object | Object only |
| Access | .value |
Direct |
| Use case | Simple values | Complex objects |
const age = ref(25)
const user = reactive({ name: 'Sam' })
π Best practice:
Use ref for primitives
Use reactive for structured state
Reusable functions using Composition API.
// useCounter.js
import { ref } from 'vue'
export function useCounter() {
const count = ref(0)
const increment = () => count.value++
return { count, increment }
}
Usage:
const { count, increment } = useCounter()
π Similar to React hooks
π Replaces mixins
| Hook | Purpose |
|---|---|
onMounted |
After DOM render |
onUpdated |
After update |
onUnmounted |
Cleanup |
import { onMounted } from 'vue'
onMounted(() => {
console.log('Mounted')
})
Allows rendering components outside the DOM hierarchy.
<teleport to="#modal">
<div>Modal Content</div>
</teleport>
π Use case:
Modals
Tooltips
Popups
Handles async components gracefully.
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
Loading...
</template>
</Suspense>
π Useful for:
API calls
Lazy loading components
Local state (ref/reactive)
Global state using Pinia (recommended)
import { defineStore } from 'pinia'
export const useStore = defineStore('main', {
state: () => ({ count: 0 })
})
π Why Pinia:
Lightweight
Type-safe
Vue 3 official
Tracks specific dependency
watch(count, (newVal) => {
console.log(newVal)
})
Automatically tracks dependencies
watchEffect(() => {
console.log(count.value)
})
π Difference:
watch → explicit
watchEffect → automatic
Lazy loading routes
Code splitting
v-once
v-memo
Use computed instead of methods
Avoid unnecessary watchers
<div v-once>{{ staticContent }}</div>
Lightweight JS representation of real DOM
Vue compares old vs new (diffing)
Updates only changed parts
π Benefits:
Efficient rendering
Better performance
Examples:
v-if
v-for
v-model
v-bind
v-on
Custom directive:
app.directive('focus', {
mounted(el) {
el.focus()
}
})
Using Vue Router:
import { createRouter, createWebHistory } from 'vue-router'
Features:
Dynamic routing
Lazy loading
Navigation guards
router.beforeEach((to, from, next) => {
if (!isAuthenticated) next('/login')
else next()
})
π Use cases:
Authentication
Authorization
Logging
<slot></slot>
<slot name="header"></slot>
Usage:
<template v-slot:header>
Header Content
</template>
Child → Parent communication
emit('update', value)
Parent:
<Child @update="handler" />
<input v-model="name" />
Modifiers:
.lazy
.trim
.number
Wait for DOM update
import { nextTick } from 'vue'
await nextTick()
π Use when:
Need updated DOM after state change
Feature-based folders
Use composables
Centralized API services
Pinia for state
Separate UI & business logic
Example:
/components
/composables
/views
/store
/services
/router
Vue 3 uses Proxy-based reactivity.
Wrap objects using Proxy
Intercept:
get → track dependency
set → trigger updates
function reactive(target) {
return new Proxy(target, {
get(obj, key) {
track(obj, key)
return obj[key]
},
set(obj, key, value) {
obj[key] = value
trigger(obj, key)
return true
}
})
}
Dependency tracking (via track)
Effect triggering (via trigger)
Uses WeakMap → Map → Set structure
π Why it matters:
Helps debug performance issues
Helps understand watcher behavior
shallowRef vs ref?refDeep reactive
Tracks nested changes
const state = ref({ count: 0 })
state.value.count++ // triggers update
shallowRefOnly tracks .value
Ignores nested changes
const state = shallowRef({ count: 0 })
state.value.count++ // β no re-render
π Use cases:
Large objects (performance optimization)
External libraries (e.g., charts)
markRaw and when to use it?Prevents Vue from making an object reactive.
import { markRaw } from 'vue'
const obj = markRaw({ name: 'test' })
π Use cases:
Third-party libraries (e.g., Mapbox, Chart.js)
Performance optimization
computed and watch?| Feature | computed | watch |
|---|---|---|
| Purpose | Derived state | Side effects |
| Caching | Yes | No |
| Sync/Async | Sync | Async |
const fullName = computed(() => first.value + last.value)
watch(fullName, (val) => {
console.log(val)
})
π Rule:
Use computed for values
Use watch for side effects (API calls)
Direct API calls in components
// api/userService.js
export const fetchUsers = () => fetch('/api/users')
// composables/useUsers.js
import { ref, onMounted } from 'vue'
import { fetchUsers } from '../api/userService'
export function useUsers() {
const users = ref([])
onMounted(async () => {
users.value = await fetchUsers()
})
return { users }
}
π Benefits:
Clean architecture
Reusable logic
Testable
Unremoved event listeners
Unstopped watchers
Third-party libraries
import { onUnmounted } from 'vue'
onUnmounted(() => {
window.removeEventListener('resize', handler)
})
π Also:
Use watchEffect cleanup
Avoid global references
<component :is="currentComponent" />
const currentComponent = ref('Home')
π Use cases:
Tabs
Feature toggles
CMS-driven UI
Lazy-loaded components:
const AsyncComp = defineAsyncComponent(() =>
import('./MyComponent.vue')
)
π Benefits:
Smaller bundle size
Faster initial load
Key usage
<div v-for="item in list" :key="item.id">
Virtual scrolling
Use libraries like:
Vue Virtual Scroller
Pagination
v-memo
<div v-memo="[item.id]">
SSR = Server-Side Rendering
Render HTML on server
Send to client
Hydrate with Vue
Nuxt.js
SEO friendly
Faster first paint
Hydration mismatch
More complexity
Process where Vue attaches event listeners to server-rendered HTML.
π Problem:
If server HTML ≠ client state → errors
Used for deep component communication.
provide('theme', 'dark')
const theme = inject('theme')
π Alternative to prop drilling
Store token (localStorage/cookie)
Use router guards
router.beforeEach((to, from, next) => {
if (!token) next('/login')
else next()
})
Use Axios interceptors
π Best practice:
Use refresh tokens
Avoid storing sensitive data in localStorage
app.config.errorHandler = (err) => {
console.error(err)
}
π Also:
Use try/catch in async calls
Error boundaries (Vue 3 feature)
Alternative to templates:
import { h } from 'vue'
export default {
render() {
return h('div', 'Hello')
}
}
π Use cases:
Dynamic UI generation
Library development
v-model under the hood?
<input v-model="name" />
Equivalent to:
<input :value="name" @input="name = $event.target.value" />
Split app into smaller independent apps.
Module Federation
Single-SPA
π Benefits:
Independent deployment
Team scalability
Tools:
Vue Test Utils
Jest / Vitest
import { mount } from '@vue/test-utils'
const wrapper = mount(Component)
expect(wrapper.text()).toContain('Hello')
| SPA | MPA |
|---|---|
| Single page | Multiple pages |
| Faster navigation | Full reload |
| Uses Vue Router | Traditional routing |
Feature-based structure
Composables for logic
API abstraction
State centralization (Pinia)
Lazy loading
Analyze with Vue DevTools
Reduce re-renders
Use computed instead of methods
Lazy load components
Optimize watchers
Use shallowRef
Use dynamic form rendering
Split into smaller components
Use validation libraries (VeeValidate)
Debounce input
Pinia (best)
provide/inject (lightweight)
Event bus (not recommended)
For 4+ years experience, interviewers expect:
Why you chose a solution
Tradeoffs
Real examples from your projects