VueJS

The key features of Vue include:

  • Declarative Rendering: Vue extends standardHTML with a template syntax that allows you to describe HTML output based on JavaScript state
  • Reactivity: Vue automatically tracksJavaScript state changes and efficiently updates the DOM when changes happen.
  • Component-Based Architecture: Applications are built using small, self-contained, and reusable components
  • Directives: Special attributes starting with v-if, v-for, and v-bind that apply reactive behavior to the DOM.
  • Virtual DOM: Vue uses a Virtual DOM to minimize actual DOM manipulations, improving performance.

  • Gentle Learning Curve: If you know HTML, CSS,and JavaScript, you can start building with Vue quickly.
  • Versatility: It can be used as a simple library to enhance static HTML or as a full-featured framework for complex SPAs.
  • High Performance: Its lightweight nature and optimized re-rendering make it very fast.
  • Great Documentation: Vue is famous in the dev community for having exceptionally clear and thorough official documentation.

As of January 2026, the latest stable version of Vue is 3.5.x. Vue 3 is the current industry standard, having replaced Vue 2 (which reached end-of-life in late 2023).

For modern development, the recommended way to start a Vue project is usingVite.

  1. Run the creator tool: Open your terminal and run: npm create vue@latest
  2. Follow the prompts: Enter your project name and select features (like TypeScript or Vue Router).
  3. Install & Run:

  • Options API: The traditional way where you define logic using an object of options like data, methods,and mounted. Best for smaller components.
  • Composition API: Introduced in Vue 3, it uses the setup attribute or function to group logic by logical concern rather than option type. It is better for large-scale applications and reusability.

Directives are special tokens in the markup that tell the library to do something to a DOM element.

  • v-bind: Dynamically binds an attribute (e.g.,:src="imagePath")
  • v-model: Creates two-way data binding on form inputs
  • v-if / v-else: Conditionally renders an element
  • v-for: Renders a list of items by looping through an array

A Single-File Component is a file with a .vue extension that encapsulates the structure (HTML), logic (JavaScript), and styling (CSS) of a component in one place. Example (MyComponent.vue):

In large applications, passing data between many nested components becomes difficult. State management libraries provide a "central store" for all components.

  • Pinia: The current officially recommended state management library for Vue 3. It is lightweight and has excellent TypeScript support.
  • Vuex: The older state management library used primarily in Vue 2 projects.

Lifecycle hooks are built-in functions that allow you to execute code at specific stages of a component's existence, such as when it is created, added to the DOM, or destroyed.

  • onMounted(): Called after the component has been mounted.
  • onUpdated(): Called after the component has updated its DOM tree due to a state change.
  • onUnmounted(): Called after the component has been removed.

Vue Router is the official router for Vue.js. It syncs the browser's URL with Vue's components, allowing you to build Single-Page Applications where the page doesn't refresh when the user navigates to different sections (like /about or /profile).

Vue Router Overview

Vue Router is the official routing library for Vue.js. It integrates deeply with the Vue core to turn a collection of components into a Single-Page Application (SPA). It manages the relationship between the URL in the browser and the components displayed on the screen without requiring a full page reload.

Core Functionalities
  • Nested Mapping: Allows you to map nested URL paths to nested components.
  • Dynamic Routing: Enables paths with parameters (e.g., /user/:id) to render the same component with different data.
  • Navigation Guards: Provides hooks (beforeEach, beforeRouteEnter) to run logic, such as authentication checks, before a user enters a route.
  • Transition Effects: Built-in support for CSS transitions when switching between routes.
  • History Modes: Offers different ways to handle URLs (HTML5 History mode vs. Hash mode).

Key Components & Concepts
Feature Description
<router-link> A component used to create navigation links. It renders as an <a> tag but prevents page refreshes.
<router-view> A functional component that acts as a placeholder where the matched component for the current route will be rendered.
createRouter The function used to initialize the router instance with a list of routes and a history mode.
Programmatic Navigation Using router.push() or router.replace() to navigate via JavaScript instead of a link.
Comparison: Web Navigation Approaches
Feature Standard Multi-Page App (MPA) Vue Router (SPA)
Page Load Full refresh for every new URL. Only components swap; no refresh.
State State is lost unless saved in cookies/storage. State is preserved in memory between views.
User Experience Slower transitions due to server requests. Instant transitions; feels like a desktop app.
SEO Naturally SEO-friendly. Requires SSR or pre-rendering for optimal SEO.

Basic Implementation Example
  1. Define Routes:
  2. Display in Template:

Both v-if and v-show are used to conditionally display elements in Vue.js. However, they differ significantly in how they handle the DOM and when they should be used for performance optimization.


Comparison Table
Feature v-if v-show
Mechanism Real rendering: Elements are physically added or removed from the DOM. CSS-based: Elements remain in the DOM; only the display property is toggled.
Initial Render Lazy: If the condition is false initially, it does nothing until it becomes true. Eager: The element is always rendered and held in the DOM regardless of the initial state.
Lifecycle Hooks Triggers mounted, unmounted, and other lifecycle hooks of child components. Does not trigger lifecycle hooks when toggling.
Performance (Toggle) Higher cost: Expensive to toggle because it constantly destroys and re-creates elements. Lower cost: Very cheap to toggle as it only switches CSS.
Performance (Initial) Lower cost: Faster if the element is never shown. Higher cost: Slower if you have many hidden elements on load.

Technical Breakdown
  • v-if (Conditional Rendering):
    • It is "real" conditional rendering because it ensures that event listeners and child components inside the conditional block are properly destroyed and re-created during toggles.
    • It supports the <template> element, allowing you to group multiple elements without adding an extra node to the DOM.
    • Works with v-else and v-else-if.
  • v-show (Conditional Visibility):
    • The element is always present in the DOM. Vue simply applies display: none; to the inline styles when the expression evaluates to false.
    • It cannot be used on the template element and does not work with v-else.

Use Case Recommendations
  • Use v-if when:
    • The condition is unlikely to change frequently during the runtime.
    • You want to reduce the initial load time by not rendering components that might never be seen.
    • You need to use v-else or v-else-if logic.
  • Use v-show when:
    • You need to toggle something very frequently (e.g., a tab, a tooltip, or a dropdown).
    • The element is critical to the layout and should be "ready" in the DOM immediately.

The v-for directive is used to render a list of items based on an array or an object. It uses a specific syntax: item in items, where items is the source data and item is an alias for the element being iterated.

  • Iterating Arrays: You can access the element and its index: v-for="(item, index) in items".
  • Iterating Objects: You can iterate through properties: v-for="(value, key, index) in myObject".
  • Range Support: It can also take an integer to repeat a template a fixed number of times: v-for="n in 10".

The Role of the :key Attribute
The :key attribute is a unique identifier used by Vue’s Virtual DOM algorithm to identify nodes when updating the list. Without keys, Vue uses an "in-place patch" strategy, which can lead to UI bugs.

Reason Detail
Efficient Updates It helps Vue identify exactly which items have changed, been added, or been removed, minimizing DOM manipulations.
State Preservation Ensures that temporary state (like text in an <input> or focus) stays with the correct item when the list is reordered.
Identity Provides a unique "signature" for each element so Vue doesn't accidentally reuse a component for a different piece of data.
Transitions Essential for Vue's <transition-group> to correctly animate items moving to new positions.

Best Practices vs. Anti-patterns
  • Do: Use unique IDs from your database (e.g., :key="user.id").
  • Don't: Use index as a key if the list can be reordered, filtered, or deleted. Using the index can cause the wrong components to be updated or destroyed.
  • Don't: Use v-for on the same element as v-if. Vue 3 gives v-if higher priority, meaning the v-if condition won't have access to variables defined in the v-for.

Implementation Example

In the Composition API, both ref and reactive are used to create reactive state. While they achieve similar goals, they handle data types and access patterns differently.


Feature ref reactive
Data Types Handles any type (Primitives: String, Number, Boolean, or Objects). Handles Objects and Arrays only (Complex types).
Access in Script Must use .value property (e.g., count.value). Accessed directly (e.g., state.count).
Access in Template Automatically unwrapped (no .value needed). Accessed directly.
Reassignment Can replace the entire value (even objects). Cannot replace the whole object; it loses reactivity if overwritten.
Destructuring Maintains reactivity. Loses reactivity unless used with toRefs.

Detailed Breakdown
  • 1. Handling Primitives
    • ref: Designed to wrap primitive values in an object to make them reactive.
      • Example: const count = ref(0).
    • reactive: Cannot hold primitives. If you pass a string or number to reactive(), it will trigger a Vue warning and won't be reactive.
  • 2. Reassignment Risks
    • ref: You can replace an entire object easily:
    • reactive: Overwriting the variable breaks the link to Vue's reactivity system:
  • 3. Destructuring Behavior

    If you destructure a reactive object, the resulting variables become plain values and stop updating the UI. To fix this, you must wrap the object in toRefs(). ref variables do not suffer from this issue when passed around.


When to Use Which?
  • Use ref by default: It is more versatile because it handles primitives and objects. Most Vue developers prefer ref for consistency.
  • Use reactive for grouped state: If you have a large form or a collection of related properties that logically belong together in a single object, reactive can make the code cleaner by avoiding .value everywhere.

Computed Properties Overview

Computed properties are reactive functions that allow you to describe a value that depends on other data properties. They are "derived" state—when the source data changes, the computed property automatically re-evaluates and updates.


Key Differences: Computed vs. Methods

The primary difference is caching. Computed properties cache their results based on their reactive dependencies, whereas methods execute every time they are called.

Feature Computed Properties Methods
Caching Cached: Only re-calculates when a dependency changes. No Caching: Runs every time the component re-renders or it is called.
Usage Used as a property (no parentheses: {{ fullName }}). Used as a function (with parentheses: {{ getFullName() }}).
Performance Better for expensive logic or heavy data processing. Can be less efficient if logic is complex and called frequently.
Purpose Designed for data transformation or derivation. Designed for event handling or specific actions.
Side Effects Should be "pure" (no API calls or DOM changes). Can contain side effects (API calls, timers, etc.).

Technical Breakdown
  • 1. The Power of Caching: If you have a computed property that filters a massive list, and that list hasn't changed, Vue will return the previously calculated result instantly. A method would force Vue to re-filter the entire list every time any unrelated part of the page updates.
  • 2. Dependency Tracking: Vue's reactivity system tracks which variables are used inside a computed property. If computedValue depends on firstName and lastName, it will only run again if one of those two variables changes.

Best Practices
  • Computed for Templates: Always use computed properties for complex logic inside your HTML to keep templates clean and readable.
  • Avoid Side Effects: Never try to change other data properties or make asynchronous calls (like fetch) inside a computed property; use Watchers for those tasks.
  • Getters and Setters: By default, computed properties are "getter-only," but you can provide a "setter" if you need to manually update the source data when the computed value is changed.

Implementation Example

Watchers Overview

In Vue.js, Watchers allow you to perform "side effects" in response to state changes. Unlike computed properties, which are used to derive new data, watchers are used for asynchronous operations, DOM manipulation, or changing other pieces of state when a specific dependency changes.


Comparison: watch vs. watchEffect

Vue 3 provides two main ways to watch data. While they share a similar goal, they differ in how they track dependencies and when they run for the first time.

Feature watch watchEffect
Tracking Explicit: You must define exactly what to watch. Implicit: Automatically tracks every reactive property used inside the function.
Initial Run Lazy: Does not run until the watched source changes (can be overridden). Eager: Runs immediately once the component is initialized.
Access to Old Value Provides both the new value and the old value. Only has access to the current state.
Use Case Best for specific state changes or when you need the previous value. Best for logic that depends on multiple sources or needs to run immediately.

Key Concepts and Features
  • Deep Watching: By default, watch is shallow. If you want to watch nested properties inside an object, you must set the { deep: true } option.
  • Immediate Execution: You can make a watch run immediately on setup (like watchEffect) by passing { immediate: true }.
  • Cleanup Side Effects: Both functions allow you to define a cleanup callback (e.g., to cancel an API request or clear a timer) that runs right before the effect re-runs or when the component is unmounted.
  • Flush Timing: You can control whether the watcher runs before or after Vue updates the DOM using the flush option ('pre', 'post', or 'sync').

Practical Examples
Using watch (Specific and Detailed)
Using watchEffect (Automatic and Immediate)

When to use Watchers vs. Computed
  • Computed: Use for transforming data to be displayed in the template (Pure functions).
  • Watchers: Use for Side Effects such as API calls, logging, changing the URL, or manual DOM updates.

Two-Way Data Binding Overview

In Vue.js, two-way data binding refers to the synchronization between the user interface (View) and the underlying data (Model). When the data changes, the UI updates; conversely, when the user interacts with the UI (e.g., typing in an input), the data updates automatically.

The v-model directive is the primary tool used to achieve this. It acts as "syntactic sugar," combining property binding and event listening into a single attribute.


How v-model Works Internally

While v-model looks like a single operation, it is actually a shorthand for two separate actions:

  1. Binding a value: It passes a data property to the element (typically via the value attribute).
  2. Listening for changes: It listens for an input event and updates the data property with the new value.
Element Type Property Bound Event Listened To
Text Inputs/Textareas value input event
Checkboxes/Radios checked change event
Select Dropdowns value change event

Key Features and Modifiers

Vue provides built-in modifiers to change how v-model behaves during user interaction:

  • .lazy: Instead of updating the data on every keystroke (input event), it only updates when the user leaves the input field (change event).
  • .number: Automatically casts the user input string into a valid JavaScript number.
  • .trim: Automatically strips whitespace from the beginning and end of the user input.

Using v-model with Components

In Vue 3, v-model is highly flexible when used on custom components:

  • Default usage: Uses a prop named modelValue and emits an event named update:modelValue.
  • Multiple v-models: You can bind multiple data points to a single component by specifying an argument (e.g., v-model:firstName="name" and v-model:lastName="surname").

Implementation Comparison
Method Code Example Manual vs. Automatic
Manual Binding <input :value="text" @input="text = $event.target.value"> Manual (verbose)
v-model <input v-model="text"> Automatic (shorthand)

Passing Data with Props

In Vue.js, data flows downward from parent components to child components using Props. Props are custom attributes you register on a component; when a value is passed to a prop attribute, it becomes a property on that component instance.


Key Characteristics of Props
  • One-Way Data Flow: Data flows down, but not up. If the parent updates the prop, the child updates automatically. However, the child must not attempt to mutate a prop directly.
  • Reactive: Props are reactive; if the parent's data changes, the child will reflect those changes immediately.
  • Type Safety: You can define the expected data type (String, Number, Object, etc.) to ensure the component is used correctly.

Implementation Steps
Step Action Description
1. Define (Child) defineProps() Use this macro in the child component to declare which props it expects.
2. Pass (Parent) v-bind or : Use the colon shorthand to pass dynamic data from the parent's state.
3. Use (Child) Template/Script Access the prop in the child's template or script logic.

Code Example
Child Component (Child.vue)
The child declares the props it is willing to receive.
Parent Component (Parent.vue)
The parent passes the data using the : shorthand.

Prop Validation Rules

It is a best practice to provide requirements for your props. If the requirements are not met, Vue will warn you in the browser console.

  • Type: String, Number, Boolean, Array, Object, Date, Function, Symbol.
  • Required: { required: true }.
  • Default: { default: 'Hello' } or a factory function for objects/arrays.
  • Validator: A custom function to validate the value logic.

Emitting Events Overview

In Vue.js, while Props allow a parent to send data down, Emits allow a child to send messages or data back up to the parent. This follows the core design pattern: "Props down, Events up".

When a child component triggers an event using $emit, the parent component can listen for that specific event and execute a method or update its own state in response.


Implementation Steps
Step Action Description
1. Declare (Child) defineEmits() Declare the events the child is allowed to fire.
2. Trigger (Child) emit('name', payload) Fire the event, optionally passing data known as the payload.
3. Listen (Parent) v-on or @ Use the @ shorthand on the child component tag to catch the event.

Detailed Code Example
Child Component (ChildButton.vue)
The child declares the event and triggers it on a button click.
Parent Component (ParentView.vue)
The parent listens for increaseBy and receives the payload automatically.

Key Rules and Best Practices
  • Kebab-case for Listeners: While you can use camelCase in JavaScript, Vue recommends using kebab-case in the HTML template (e.g., @update-value).
  • Validation: You can validate emits in Vue 3 by passing an object to defineEmits that checks if the payload is valid before sending it.
  • One-Way Data Flow: Never change a prop inside the child to communicate with the parent; always emit an event so the parent can change its own state.
  • Multiple Arguments: You can pass multiple arguments as a payload: emit('update', arg1, arg2).

Teleport Overview

Teleport is a built-in component in Vue 3 that allows you to "transport" a piece of a component's template to a different part of the DOM tree, outside of the component's hierarchical structure.

Even though the element is rendered in a different location (like the <body> or a specific #container div), it still behaves like a normal child of the original component—meaning it can access the component's state, props, and scoped styles.


Why is Teleport Necessary?

In standard Vue development, components are rendered within their parents. However, certain UI elements can be broken by CSS properties like z-index, overflow: hidden, or position: relative in the parent container.

Use Case Problem Without Teleport Solution With Teleport
Modals/Dialogs May get cut off by overflow: hidden on a parent. Render at the top level of the <body> to avoid clipping.
Full-screen Overlays Hard to manage z-index depth. Moves the element to a global container for easy layering.
Notifications Needs to appear on top of all UI. Teleport to a dedicated #toast-container at the root.
Tooltips Positioning can be skewed by parent transform properties. Positions relative to the viewport or body.

How to Use Teleport

The <Teleport> component requires a to target, which can be a CSS selector string (like an ID or class) or an actual DOM element.

Example: Creating a Modal

Key Features and Behaviors
  • Logical vs. Physical: It remains a logical child of the component. You can pass props to it and emit events from it as if it hadn't moved.
  • Disabled State: You can toggle the teleportation using the :disabled prop. When disabled, the content stays inside the original component structure.
  • Multiple Teleports: Multiple <Teleport> components can send content to the same target element. They will simply be appended one after another.
  • Scoped CSS: Styles defined in <style scoped> will still apply to the teleported content because it remains part of the virtual component tree.

Slots are a powerful distribution mechanism in Vue.js that allow a parent component to inject HTML, components, or plain text into a child component’s template. This makes components highly reusable by allowing the parent to define the "content" while the child defines the "layout".


Types of Slots
Slot Type Description Usage Scenario
Default Slot The unnamed, catch-all slot. Simple wrappers like buttons or alerts.
Named Slots Specific slots identified by a name (using v-slot:name or #name). Complex layouts with multiple sections (e.g., Header, Main, Footer).
Scoped Slots Slots that pass data from the child back to the parent. Lists or tables where the child manages data but the parent defines the UI.

Understanding Scoped Slots

Normally, a parent cannot access data inside a child's scope. Scoped Slots bridge this gap by allowing the child to "provide" data to the slot's content in the parent.

The Workflow:

  1. Child: Defines a <slot> and binds data to it using attributes (props).
  2. Parent: Receives that data via the v-slot directive value.

Implementation Example

Child Component (UserList.vue):
The child iterates through data but lets the parent decide how to display each item.

Parent Component:
The parent accesses the userData via the #item slot.


Key Benefits of Scoped Slots
  • Inversion of Control: The child manages the logic (fetching, filtering, or looping), while the parent manages the visual representation.
  • Flexibility: You can use the same component for a "Card View" in one part of your app and a "Table View" in another, just by changing the slot template.
  • Encapsulation: Keeps the child component focused on data/state management without hardcoding UI styles.

KeepAlive Overview

<KeepAlive> is a built-in component in Vue that caches component instances when they are dynamically toggled.

Normally, when a component is switched out (e.g., via v-if or <component :is="...">), it is destroyed and its state is lost. Wrapping these components in <KeepAlive> preserves their state and avoids the performance overhead of re-creating the DOM and re-fetching data.


Key Behaviors and Lifecycle

When a component is cached by <KeepAlive>, its standard lifecycle hooks behave differently, and two specialized hooks are introduced:

Lifecycle Hook Behavior Inside <KeepAlive>
onMounted Only fires the first time the component is created.
onUnmounted Never fires while the component is being cached.
onActivated Fires every time the component becomes visible (re-enters the DOM).
onDeactivated Fires every time the component is hidden (removed from DOM but kept in memory).

Core Properties

You can control which components are cached using the following props:

  • include: Only components with matching names will be cached (String, Regex, or Array).
  • exclude: Any component with a matching name will not be cached.
  • max: Limits the maximum number of component instances to cache. When the limit is reached, the least recently used (LRU) instance is destroyed.

Common Use Cases
Use Case Benefit
Tabbed Interfaces Switching between tabs preserves the user's scroll position and form input values.
List Views Navigating back from a "Detail" page to a "List" page doesn't trigger a new API call to reload the list.
Multi-step Forms Prevents data loss when a user navigates back to a previous step to make corrections.

Implementation Example
Example: Caching Dynamic Components

Asynchronous Components Overview

In large applications, loading every component at once can lead to a massive initial JavaScript bundle, causing slow page loads. Asynchronous Components allow you to split your app into smaller chunks and load components from the server only when they are actually needed.

In Vue 3, this is achieved using the defineAsyncComponent function.


Implementation Approaches
Method Description Use Case
Basic Usage A simple function that returns a Promise (usually via a dynamic import()). Standard route-level or tab-level components.
Advanced Options An object configuration that handles loading and error states. Mission-critical components where user feedback during loading is required.
With Suspense Integration with the <Suspense> built-in component. Coordinating multiple async dependencies (like data fetching + component loading).

Basic vs. Advanced Syntax
1. Basic Syntax

The most common way to lazy-load a component:

2. Advanced Configuration

For a better user experience, you can manage the "waiting" period:


Key Benefits
  • Code Splitting: Build tools like Vite or Webpack automatically recognize dynamic imports and create separate .js files for them.
  • Reduced Initial Load: Users only download the code for the page they are currently visiting.
  • Improved Performance: Smaller entry bundles lead to faster "Time to Interactive" (TTI).

Using with <Suspense>

Vue 3's <Suspense> component can coordinate the loading state of an entire tree of async components. It provides "slots" for the ready state and the loading (fallback) state.

Provide and Inject Overview

Provide and Inject is a feature in Vue used for dependency injection. It allows a "grandparent" or ancestor component to serve as a dependency provider for all its descendants, regardless of how deep the component hierarchy is.

This solves the problem of "Prop Drilling," where data must be passed through multiple layers of intermediate components that don't actually need the data themselves.


How It Works
Action Component Macro / Function Description
Provide Ancestor provide(key, value) Defines the data or methods to be shared with descendants.
Inject Descendant inject(key, default?) Retrieves the data provided by an ancestor using the unique key.

Provide/Inject vs. Props
Feature Props Provide / Inject
Data Flow Direct (Parent to Child). Long-distance (Ancestor to any Descendant).
Coupling High: Components must be explicitly linked. Low: Intermediate components are unaware of the data.
Scalability Becomes messy with deep nesting (Prop Drilling). Clean for global-like state within a specific tree.
Visibility Explicit in the template. Implicit; can be harder to track where data originates.

Implementation Example
The Ancestor Component
The Deeply Nested Child

Best Practices
  • Reactivity: To keep the injected data reactive, ensure you provide a ref or reactive object.
  • Symbol Keys: For large applications, use Symbols as keys instead of strings to avoid naming collisions between different plugins or components.
  • Mutations: If a child needs to change the data, it is best practice to provide a function (like toggleTheme) that performs the mutation in the ancestor, rather than letting the child mutate state directly.
  • Plugin Usage: This pattern is the primary way Vue plugins (like Vue Router or Pinia) make their instances available to your entire app.

Component Registration Overview

In Vue.js, you must register components so that Vue knows how to locate and render them when they are used in a template. There are two primary ways to do this: Global and Local registration.


Comparison Table
Feature Global Registration Local Registration
Declaration Registered on the app instance (app.component). Registered within a specific component file.
Availability Available everywhere in the application. Only available in the component that imports it.
Bundle Size Heavier: Included in the main bundle even if unused. Lighter: Supports tree-shaking; only loaded if needed.
Dependency Tracking Harder: Difficult to see where a component is used. Clear: Explicit imports make dependencies easy to trace.
Best For Common UI elements (Buttons, Inputs, Icons). Feature-specific or complex sub-components.

Implementation Differences
1. Global Registration

Registered in the main entry file (usually main.js). Once registered, you do not need to import them again in any .vue file.

2. Local Registration

The component is imported and used only where it is needed. This is the recommended approach for most components.


Pros and Cons
Global Registration
  • Pros: Extremely convenient for "building blocks" (Base components) used in almost every view.
  • Cons: It creates a "Global Namespace" which can lead to name collisions. It also bloats the initial JavaScript file because build tools cannot remove unused global components.
Local Registration
  • Pros: Keeps the relationship between components explicit. Improves performance through tree-shaking.
  • Cons: Can feel repetitive if you have to import the same 5-10 "Base" components in every single file.

Dynamic Components Overview

In Vue.js, Dynamic Components allow you to switch between different components at the exact same mount point without changing the URL or using complex v-if/v-else-if chains. This is achieved using the built-in <component> element with the special is attribute.


Key Features
  • The :is Attribute: This can accept either a string (the name of a registered component) or the actual component object itself.
  • State Management: By default, when you switch away from a component, it is destroyed. To preserve its state (like form inputs or scroll position), wrap it in a <KeepAlive> component.
  • Reactivity: The component updates immediately whenever the value passed to :is changes.

Implementation Comparison
Approach Syntax Example Best For
String-based <component is="HomeView" /> Globally registered components or basic HTML tags.
Object-based <component :is="CurrentComponent" /> Components imported via Composition API (<script setup>).
Conditional v-if="type === 'A'" Switching between only 2 or 3 static options.

Code Example (Composition API)

In this example, we use a shallow reference to store the component object to avoid unnecessary reactivity overhead on the component definition itself.


Common Use Cases
  • Tabbed Interfaces: Switching between "Settings," "Profile," and "Security" views within a single container.
  • Dashboards: Rendering different types of "widgets" based on user configuration.
  • Page Builders: Rendering content blocks (e.g., Image, Text, Video) based on a JSON response from a CMS.
Performance Tip: When using the Composition API, always store components in a shallowRef() instead of ref(). Since component objects are complex, ref() tries to make every internal property reactive, which can lead to performance warnings and unnecessary CPU overhead.

Composables Overview

In Vue 3, a Composable is a function that leverages the Composition API to encapsulate and reuse stateful logic. Think of it as a way to "package" a specific feature (like tracking mouse coordinates or fetching data) so it can be dropped into any component.

By convention, composable names start with "use," such as useMouse, useFetch, or useAuth.


Composables vs. Mixins

Before Vue 3, Mixins were the primary way to share code; however, they had significant flaws that Composables solve:

Feature Mixins (Vue 2) Composables (Vue 3)
Data Source Implicit: Hard to tell which mixin a property came from. Explicit: Values are returned and destructured in the component.
Naming Conflicts High Risk: Multiple mixins can use the same property names, causing collisions. No Risk: You can rename destructured variables (e.g., const { data: user } = useFetch()).
Reactivity Less flexible; logic is spread across options (data, methods). Built entirely on the Reactivity API (ref, computed).
Logic Organization Scattered: Logic is split by option type. Grouped: Related state and functions stay together.

Standard Composable Structure

A composable typically follows this pattern:

  1. Define state using ref or reactive.
  2. Define methods to modify that state.
  3. Use lifecycle hooks (like onMounted) if needed.
  4. Return the state and methods.
Example: useCounter.js

Using a Composable in a Component

Why They Are Better
  • Tree-shaking: If you don't use a specific function from a composable, modern build tools can remove it from the final bundle.
  • Ease of Testing: Since composables are just functions, they can be tested in isolation more easily than components.
  • SSR Compatibility: Composables are designed to work smoothly with Server-Side Rendering (SSR).

Lifecycle Hooks Overview in the Composition API

In the Composition API (used within the setup() function or <script setup>), lifecycle hooks are accessed as imported functions. These functions accept a callback that executes when the specific lifecycle event occurs.


Mapping Options API to Composition API

Most hooks have a direct equivalent, usually prefixed with "on". Note that beforeCreate and created do not have equivalents because the setup() function itself acts as these hooks.

Options API Hook Composition API Hook Execution Timing
beforeCreate / created Not needed Code runs directly inside setup().
beforeMount onBeforeMount() Right before the component is added to the DOM.
mounted onMounted() After the component is inserted into the DOM.
beforeUpdate onBeforeUpdate() When data changes, but before the DOM re-renders.
updated onUpdated() After the DOM has been patched with changes.
beforeUnmount onBeforeUnmount() Right before the component is destroyed.
unmounted onUnmounted() After the component and its listeners are removed.

Implementation Example

To use a hook, you must import it from the 'vue' package. You can also call the same hook multiple times within one setup() to keep related logic together.


Key Rules for Usage
  • Synchronous Registration: Hooks must be called synchronously during the execution of setup(). You cannot call them inside an async function or setTimeout.
  • Multiple Hooks: Unlike the Options API, you can have multiple onMounted() calls, which is essential for organizing code within Composables.
  • Internal State: Hooks have access to the component's internal state (refs, computed properties) because they are defined within the same scope.

Specialized Hooks

In addition to standard hooks, Vue provides:

  • onActivated / onDeactivated: Used exclusively with components cached via <KeepAlive>.
  • onErrorCaptured: Used to catch errors originating from any descendant component.

Overview of <script setup>

Introduced in Vue 3.2, <script setup> is a compile-time syntactic sugar for using the Composition API inside Single-File Components (SFCs). It is currently the industry-recommended standard for writing Vue components because it significantly reduces boilerplate and improves developer experience.


Key Benefits and Recommendations
Feature Standard <script> with setup() <script setup>
Boilerplate High (requires export default and return). Low (everything is automatically exposed).
Variable Exposure Must manually return variables to use in templates. Top-level variables are automatically available.
Performance Standard runtime overhead. Better performance: Compiled into a more efficient render function.
Type Support Good. Superior: Better IDE type-inference for TypeScript users.
Component Usage Must register components in a components object. Just import it and use it directly in the template.

Why It Is Recommended
  • Conciseness: You write significantly less code. You don't have to repeat variable names in a return block.
  • Ergonomics: It feels more like writing standard JavaScript/TypeScript.
  • Template Optimization: Because the compiler knows which variables are used in the template, it can generate more optimized code than the traditional setup() function.
  • Better Integration with Macros: It allows the use of Compiler Macros like defineProps() and defineEmits(), which don't need to be imported.

Comparison Example
Traditional Composition API
The Modern <script setup> Way

Compiler Macros

When using <script setup>, specialized functions called "macros" are used to handle component-level options without imports:

  • defineProps(): Declares props.
  • defineEmits(): Declares events.
  • defineExpose(): Explicitly limits which properties are accessible via a template ref (by default, <script setup> components are "closed").

Template Refs Overview

While Vue's data-driven approach handles most DOM updates, there are times when you need direct access to a DOM element (e.g., to focus an input, integrate a third-party library like D3.js, or measure an element's dimensions). Template Refs allow you to create a reference to a specific element or child component.


How to Implement Template Refs

In the Composition API, template refs are created by defining a ref with an initial value of null and then binding it to an element in the template using the ref attribute.

Step Action Code Example
1. Create Ref Initialize a ref with null. const myInput = ref(null)
2. Bind in Template Add ref="myInput" to the element. <input ref="myInput" />
3. Access Use the .value property. myInput.value.focus()
Warning: You can only access the ref after the component is mounted. If you try to access myInput.value inside setup() directly (outside of a hook), it will be null.

Usage in Lifecycle Hooks

Because the DOM element doesn't exist until Vue renders it, you must use onMounted to interact with it.


Refs on Components vs. Elements
Target Result of ref.value
HTML Element Returns the actual DOM node (e.g., HTMLInputElement).
Vue Component Returns the Component Instance.
A Note on defineExpose

When using <script setup>, components are private by default. If a parent uses a template ref to access a child component, it won't see any of the child's variables unless the child explicitly allows it using defineExpose:


Refs inside v-for

When ref is used inside a v-for loop, the resulting ref should be handled as an Array containing all the elements after the component is mounted. In Vue 3, this requires binding the ref to a function or using a reactive array.

Understanding toRefs

In Vue 3, toRefs is a utility function used to convert a reactive object into a plain object where each property is a ref pointing to the original property of the source object.

It is primarily used to solve the problem of losing reactivity during destructuring or when using the spread operator (...) on a reactive object.


The Problem: Destructuring reactive

When you use a reactive object and destructure it using standard JavaScript syntax, the resulting variables are disconnected from Vue's reactivity system. They become plain, static values.

Action Resulting State
Normal Access (state.count) Reactive: UI updates automatically when the value changes.
Destructured (const { count } = state) Static: The variable count is just a local copy; changes don't trigger UI updates.
Using toRefs Reactive: Each property is wrapped in a ref, maintaining the link to the original state.

Technical Breakdown
  1. Why Reactivity Fails: The reactive function uses JavaScript Proxies. When you destructure a proxy, you are performing a value assignment (e.g., const count = state.count). If the value is a primitive (number, string, boolean), it is copied by value, and the Proxy is bypassed.
  2. How toRefs Fixes It: It creates a "proxy" object where every property is a getter/setter that points back to the original object. Because these properties are refs, they maintain reactivity even when separated from the parent object.

Implementation Example

Common Use Cases
  • Returning from Composables: To allow users to destructure the returned state without losing reactivity.
    Example: const { user, status } = useAuth()
  • Destructuring Props: To keep props reactive inside setup() when you don't want to use the props.xxx prefix everywhere.

Quick Comparison: toRef vs toRefs
Utility Description Typical Use
toRef Creates a ref for a single property. Linking one specific prop to a local ref.
toRefs Converts all properties into refs. Destructuring an entire reactive object/props.

Pinia Overview

Pinia is the official state management library for Vue.js, designed to replace Vuex. It provides a central "store" to house data that needs to be shared across many components, such as user authentication info, shopping carts, or global settings.

While Vuex was the standard for years, Pinia was built specifically to leverage the Composition API and modern TypeScript features, making it the default choice for Vue 3.


Why Pinia is Preferred over Vuex
Feature Vuex (Legacy) Pinia (Modern)
Complexity High: Requires Mutations, Actions, and Getters. Low: Actions act like methods; Mutations are removed.
TypeScript Difficult: Requires complex manual typing. Native: Automatic type inference and full TS support.
Boilerplate High: Lots of code required to set up a store. Minimal: Feels like writing a standard Composable.
Modularity Single Store: Uses namespaced modules. Multi-Store: Each store is independent and auto-bundled.
DevTools Standard support. Enhanced support with time-travel and better inspection.

Core Differences in Logic

1. The Removal of Mutations

In Vuex, you could only change state via Mutations (synchronous). This added a layer of abstraction that was often redundant.

  • Pinia Approach: You change state directly or within an Action. There are no mutations, simplifying the mental model.

2. Modular by Design

Vuex uses a single "Root Store" with nested "Modules," making it easy to create a monolithic mess.

  • Pinia Approach: You define separate stores (e.g., useUserStore.js, useCartStore.js). You only import what you need, enabling better code-splitting.

Anatomy of a Pinia Store

A Pinia store consists of three main parts, mirroring the logic of a Vue component:

Component Part Pinia Part Description
ref() / reactive() State The central source of truth (reactive properties).
computed() Getters Derived state based on the current state (cached).
function() Actions Methods that mutate state or handle async logic (API calls).

Code Example (Setup Store)

Usage in a component:


When to Use Pinia?
  • When state needs to be shared across multiple routes or unrelated components.
  • When you need to persist data (like user preferences) across the session.
  • When "Prop Drilling" (passing data through 5 layers of components) makes your code unreadable.

Defining a Pinia Store

In Pinia, there are two ways to define a store: Option Stores (similar to the Options API) and Setup Stores (similar to the Composition API). Both patterns organize the store into three fundamental parts: State, Getters, and Actions.


The Three Core Pillars
Pillar Equivalent Purpose
State data() The central source of truth. In Option stores, it must be a function returning the initial state.
Getters computed() Values derived from the state. They are cached and only re-calculate when dependencies change.
Actions methods() Functions used for business logic and side effects (API calls). Unlike Vuex, these can be async.

1. Option Store Syntax

This syntax is structured as an object and is often preferred by those transitioning from Vuex or those who like a strictly separated structure.


2. Setup Store Syntax

This is the modern approach. It uses functions like ref() and computed() and feels exactly like writing a standard Composable.


Accessing the Store in a Component

You import the specific store "use" function and initialize it inside your component's setup phase.


Key Rules & Tips
  • ID Requirement: Every store must have a unique ID (the first argument) so Pinia can connect it to the DevTools and internal registry.
  • storeToRefs: If you destructure state or getters (e.g., const { count } = store), you must wrap the store in storeToRefs(store) to maintain reactivity.
  • Direct Mutations: While Pinia allows store.count++, it is cleaner to keep logic inside Actions for better debugging and reusability.

Navigation Guards Overview

Navigation Guards are hooks provided by Vue Router that allow you to "guard" or control access to specific routes. They are primarily used to redirect users, cancel navigation, or perform data fetching before a page is rendered.

Think of them as middleware for your URLs. They are essential for security (e.g., protecting an Admin panel) and user experience (e.g., warning a user before they leave a half-filled form).


Types of Navigation Guards
Category Guard Name Scope Common Use Case
Global beforeEach Every single route change. Checking for Auth tokens/Login state.
Global afterEach After navigation is confirmed. Changing page titles or sending analytics.
Per-Route beforeEnter Defined inside the route config. Permissions for specific admin routes.
In-Component onBeforeRouteLeave Inside a .vue component. Unsaved changes confirmation.

The Global beforeEach Guard

This is the most frequently used guard. In Vue Router 4, we typically use return values instead of the old next() callback:

  • to: The target route object.
  • from: The current route object.
  • Return false: Cancels the navigation.
  • Return { name: 'Login' }: Redirects the user.
  • Return undefined (or nothing): Validates the navigation.
Example: Authentication Guard

The Full Navigation Flow

When a navigation is triggered, the hooks run in this strict sequence:

  1. beforeRouteLeave (in the component being left).
  2. beforeEach (Global).
  3. beforeRouteUpdate (if params changed but component is reused).
  4. beforeEnter (in the route config).
  5. beforeRouteEnter (in the new component).
  6. beforeResolve (Global - right before confirmation).
  7. afterEach (Global - navigation finished).

Key Features
  • Route Meta Fields: You can add meta: { requiresAuth: true } to routes, which guards check to make decisions.
  • Asynchronous: Guards can be async, allowing you to wait for API responses (like session validation).
  • Composition API: Use onBeforeRouteLeave and onBeforeRouteUpdate directly inside <script setup>.

Example: Preventing Unsaved Changes

Dynamic Route Matching Overview

In Vue Router, Dynamic Route Matching allows you to map a single route pattern to multiple URLs. Instead of defining a separate route for every user or product, you use a param (prefixed with a colon :) to capture dynamic values from the URL.

When a user visits /user/123 or /user/abc, the same component is rendered, but the specific ID is made available to the component.


Implementation Steps
Step Action Example / Code
1. Define Route Use a colon : before the param name. { path: '/user/:id', component: UserProfile }
2. Navigate Pass the value in the URL. <router-link to="/user/123">View User</router-link>
3. Access Data Use the useRoute hook. const id = route.params.id

Accessing Params in Components

With the Composition API, you use the useRoute function to access the current route's state.


Key Considerations
1. Reacting to Param Changes

When navigating from /user/1 to /user/2, the component instance is reused. Because the component isn't destroyed and re-mounted, lifecycle hooks like onMounted will not fire again.

To handle this, you can:

  • Watch the params: Use watch(() => route.params.id, (newId) => { ... }).
  • Use a Key: Add :key="$route.fullPath" to your <router-view /> to force a full re-mount (though this may impact performance).
2. Matching Patterns

You can use Regex to fine-tune what a dynamic segment matches:

  • Numeric only: { path: '/user/:id(\\d+)' }
  • Optional params: { path: '/user/:id?' }
  • Repeatable params: { path: '/files/:path+' } (matches /files/a/b/c)

Programmatic Navigation

You can also navigate to dynamic routes using the router.push method:


Summary of Route Parameters
Feature Syntax Example URL Result in route.params
Single Param /:id /123 { id: '123' }
Multiple Params /:category/:id /books/45 { category: 'books', id: '45' }
Catch-all (404) /:pathMatch(.*)* /any/bad/url { pathMatch: ['any', 'bad', 'url'] }

Lazy Loading Routes Overview

Lazy Loading is a technique where you defer the loading of route-specific code until the user actually navigates to that route. Instead of downloading the entire application's JavaScript in one massive "vendor" bundle, the application is split into smaller chunks.

In Vue Router, this is implemented using dynamic imports.


How It Works

When you define a route with a standard import, that component is bundled into the initial load. When you use a dynamic import function, the build tool (like Vite or Webpack) automatically creates a separate .js file for that route.

Feature Standard Import Lazy Loaded (Dynamic)
Syntax import Home from './Home.vue' () => import('./Home.vue')
When Loaded At application startup. Only when the user clicks the link.
Initial Bundle Size Larger (slower "Time to Interactive"). Smaller (faster initial load).

Implementation Example

Why It Is Good for Performance
  • Faster Initial Load: By reducing the "Main Thread" work required to parse JavaScript when a user first lands on your site, the page becomes interactive much sooner.
  • Reduced Data Usage: Users who only visit the landing page don't "pay" the data cost for complex parts of the app (like an Admin Dashboard) they might never see.
  • Efficient Caching: If you update the code for just one page, the browser only needs to re-download that specific chunk.

Grouping Chunks (Advanced)

Sometimes you want to group several related routes into the same chunk (e.g., all "User Settings" pages). You can do this using "Magic Comments":


Summary of Benefits
  • Lowers TTI (Time to Interactive).
  • Improves Lighthouse/Core Web Vitals scores.
  • Enables better scalability for enterprise-level apps.

404 Catch-all Routes Overview

In Vue Router, a 404 page (or "Not Found" page) is handled by defining a specific route at the end of your routes array that uses a custom regular expression to match any URL that hasn't been caught by previous definitions.

Since Vue Router matches routes in the order they are defined, this "Catch-all" route must always be the last entry in your configuration.


Implementation Syntax

In Vue Router 4 (Vue 3), the syntax uses a custom parameter with a regular expression (.*)*.

Syntax Component Meaning
:pathMatch The name of the parameter where the "bad" URL will be stored.
(.*) The regular expression telling Vue to match any character sequence.
* Makes the parameter repeatable, allowing it to capture nested paths (e.g., /lost/deep/here).

Code Example

1. Define the Route

2. The NotFound Component

You can even display the invalid path to the user using the pathMatch parameter.


Advanced Use Cases
  • Specific Sub-sections: You can catch 404s within a specific path. For example, path: '/user/:pathMatch(.*)*' would catch any invalid URL starting with /user/.
  • Programmatic 404s: Sometimes a route is valid (e.g., /user/123), but the data doesn't exist in your database. In this case, you can manually trigger a redirect to your 404 page:

Best Practices
  1. Placement: Always place the catch-all route at the very bottom. If you place it at the top, it will match every URL, and your actual pages will never load.
  2. Lazy Loading: Always lazy load the 404 component. Since most users (hopefully) won't see it, there's no need to include it in the initial bundle.
  3. Naming: Give it a name like NotFound so you can easily redirect to it from navigation guards.

Vite Overview

Vite (French for "fast," pronounced /veet/) is a modern build tool and development server created by Evan You (the creator of Vue). It was designed to address the performance bottlenecks of Webpack-based tools like Vue CLI, especially as projects grow larger.

As of Vue 3, Vite is the official recommendation for starting new projects, effectively replacing the Vue CLI.


Key Differences: Vite vs. Vue CLI (Webpack)

The fundamental difference lies in how they handle code during development.

Feature Vue CLI (Webpack) Vite
Dev Server Start Slow: Bundles the entire app before serving. Instant: Serves source code via Native ESM.
Hot Module Replacement Performance degrades as the project grows. Constant speed: Only replaces the changed module.
Build Tooling Uses Webpack. Uses Rollup for highly optimized builds.
Dependency Pre-bundling Done during the main bundling process. Done once using esbuild (written in Go, 10–100x faster).
Configuration Often complex (vue.config.js). Simpler and leaner (vite.config.js).

Why is Vite so much faster?
1. Cold Starts
  • Webpack: Must crawl your entire dependency graph and build a complete bundle before the server can start. If you have 1,000 components, it processes 1,000 components first.
  • Vite: Categorizes modules into "dependencies" and "source code." It serves your source code over Native ESM. The browser requests the specific file it needs via an import statement, and Vite serves it on demand.
2. Updates (HMR)
  • Webpack: When a file changes, it re-bundles the affected chunk. Even with caching, the re-bundling time increases with project size.
  • Vite: Hot Module Replacement (HMR) is decoupled from the total number of modules. It simply invalidates the chain between the changed module and its closest HMR boundary.

Comparing the Build Process

While Vite is "unbundled" during development, it still bundles your code for production to ensure the best performance in the browser.

Stage Development Production
Vite Engine Native ESM + esbuild Rollup
Result Rapid startup, instant updates Highly optimized, small static assets

Migration Status
  • Vue CLI: Now in maintenance mode. It still works, but no new major features are being added.
  • Vite: The standard. It supports Vue, React, Svelte, and vanilla JS. It is the engine behind Nuxt 3.

Custom Directives Overview

While Vue provides a robust set of default directives (like v-model or v-show), Custom Directives allow you to write reusable logic that interacts directly with the DOM. They are best used when you need low-level DOM access that isn't easily handled by standard component logic.

By convention, if you name a directive vFocus, it is used in the template as v-focus.


The Directive Lifecycle Hooks

A directive object provides several "hooks" that trigger at different stages of an element's life. These are similar to component lifecycle hooks but specifically for the element the directive is attached to.

Hook Timing
created Called before the element's attributes or event listeners are applied.
beforeMount Called when the directive is first bound to the element, before it's in the DOM.
mounted (Most Common) Called when the element is inserted into the parent DOM.
beforeUpdate Called before the containing component's VNode is updated.
updated Called after the containing component and its children have updated.
beforeUnmount Called before the element is removed from the DOM.
unmounted Called when the element is removed.

Implementation Example: Auto-Focus

1. Local Registration (<script setup>)

In <script setup>, any camelCase variable that starts with v can be used as a directive.

2. Global Registration

Useful for utilities you want available across your entire application.


Directive Arguments and Values

Directives can accept values, arguments, and modifiers, just like v-on:click.stop. These are passed via the binding object.

Feature Syntax Binding Property
Value v-color="'blue'" binding.value (the string 'blue')
Argument v-color:background binding.arg (the string 'background')
Modifiers v-color.delay binding.modifiers (an object { delay: true })

Example: Dynamic Styling Directive


When to Use Custom Directives?
  • Third-party DOM Libraries: Integrating libraries like Tooltip.js or Input masking.
  • Low-level Animations: Triggering specific CSS transitions on scroll.
  • UI Utilities: Auto-focusing, clicking outside to close a menu, or image lazy-loading.

Note: Always prefer Components or Composables first. Only use Custom Directives when you truly need to touch the raw HTML element.

Virtual DOM Overview

The Virtual DOM (VDOM) is a lightweight, JavaScript-based representation of the actual Document Object Model (DOM). It is essentially a "tree" of plain JavaScript objects (called VNodes) that mimic the structure of the real HTML tags you see in the browser.

Vue uses the Virtual DOM to optimize updates. Instead of re-rendering the entire page every time a piece of data changes, Vue updates the "draft" (Virtual DOM) first, finds the differences, and only applies the necessary changes to the real browser DOM.


How the Process Works

Vue's rendering pipeline follows three main steps:

  1. Render: The component's template is compiled into a "Render Function," which returns a Virtual DOM tree.
  2. Reconcile (Diffing): When state changes, a new Virtual DOM tree is created. Vue compares the new tree with the old one using a highly optimized Diffing Algorithm.
  3. Patch: Vue identifies exactly what changed (e.g., just one text node or one CSS class) and "patches" only those specific parts of the real DOM.

Why use a Virtual DOM?
Feature Real DOM Virtual DOM
Speed Slow: Touching the DOM is expensive for the browser. Fast: Operations are just JS object manipulations.
Efficiency Updates the whole element/tree. Updates only the changed attributes or nodes.
State Tracking Manual: You must track what to update. Automated: Vue tracks dependencies and updates for you.

Vue 3 Optimizations: The "Compiler-Informed" VDOM

One of the reasons Vue 3 is faster than other VDOM frameworks (like React) is that its compiler is "smart." During the build step, it analyzes your template and adds Patch Flags.

  • Static Hoisting: Vue identifies parts of your template that never change and hoists them out of the render function so they are created only once.
  • Patch Flags: Vue marks dynamic elements with a "flag" (e.g., "only text changes"). During diffing, Vue skips checks for things it knows won't change.
  • Block Tree: Vue flattens the tree structure during diffing, so it only loops through dynamic nodes rather than the entire nested HTML structure.

The Lifecycle of a Change
  1. Trigger: A reactive variable (e.g., count.value++) changes.
  2. Notify: The "Effect" associated with the component's render function is triggered.
  3. Virtual Update: A new VNode tree is generated.
  4. The Patch: Vue sees that only the <span> text changed and executes el.textContent = newCount.

Nuxt.js Overview

Nuxt.js is an open-source framework built on top of Vue.js that provides an opinionated, "batteries-included" environment for building production-ready applications. While Vue.js is a library focused on the UI layer, Nuxt is a full-stack framework that handles routing, meta tags, state management, and most importantly, different rendering modes.


Nuxt vs. Standard Vue (Vite)
Feature Standard Vue (Client-Side) Nuxt (Server-Side/Static)
Rendering Client-Side Rendering (CSR) only. SSR, SSG, or Hybrid Rendering.
SEO Difficult: Search engines see a blank HTML file initially. Excellent: Content is pre-rendered on the server.
Routing Manual: You must configure vue-router. File-based: Routes are auto-generated from your folder structure.
Folder Structure Flexible/Unstructured. Opinionated: Specific folders for pages, components, server, etc.
Performance Larger initial JS bundle; slower FCP. Optimized: Faster "First Contentful Paint" (FCP).

What is SSR (Server-Side Rendering)?

In a standard Vue app, the browser receives a nearly empty HTML file and a large JavaScript bundle. The browser then "builds" the page. In SSR, the Nuxt server executes the Vue code, generates the final HTML string, and sends a fully-formed page to the browser.

When to use SSR?
  • SEO is Critical: If your site relies on Google, Bing, or social media previews (Twitter/Open Graph), SSR ensures robots can read your content instantly.
  • Slow Devices/Networks: SSR offloads the heavy lifting of the first render to the server, making the site feel faster on low-end mobile devices.
  • Content-Heavy Sites: Blogs, e-commerce stores, and news portals benefit most from SSR.

Key Nuxt Features
  • Auto-Imports: You don't need to import ref, computed, or your own components; Nuxt handles it automatically.
  • Server Engine (Nitro): Nuxt includes a powerful server-side engine that allows you to write API routes (like Express) directly inside your Vue project in a server/ directory.
  • SEO Utilities: Simple composables like useHead() or useSeoMeta() make managing page titles and descriptions effortless.
  • Nuxt Modules: A massive ecosystem of modules (Nuxt Auth, Nuxt Image, Tailwind, etc.) that can be added with a single line of configuration.

The Rendering Modes of Nuxt
Mode How it Works Best For
SSR Server generates HTML on every request. Dynamic sites with user-specific data (Dashboards).
SSG HTML is generated at "build time" as static files. Documentation, Blogs, Portfolio sites.
Hybrid Different rules for different routes. Large sites where some pages are static and others are dynamic.

Data Flow Overview

In Vue.js, the way data moves between the state and the UI determines how predictable and maintainable your application is. While Vue is famous for its Two-way Binding convenience, the underlying architecture for component communication is strictly One-way Data Flow.


Comparison Table
Feature One-way Data Flow Two-way Binding
Direction Source → View (Downwards only). Source ↔ View (Bidirectional).
Mechanism Props down, Events up. v-model directive.
Predictability High: You always know where the change started. Lower: Changes in the UI automatically mutate the state.
Primary Use Parent-to-Child component communication. Form inputs (input, checkbox, select).
Control High: Logic can intercept/validate data. Low: Data is updated immediately on input.

1. One-way Data Flow (The Rule)

In Vue, props are read-only. A child component should never mutate a prop directly. If the child needs to change the data, it must emit an event to the parent, and the parent updates the state.

  • Logic: Data flows down (Props), Actions flow up (Events).
  • Benefit: Prevents "spaghetti code" where child components accidentally change parent state, making debugging difficult.

2. Two-way Binding (The Convenience)

Two-way binding means that when the data changes in the JavaScript, the UI updates; conversely, when the user types in the UI, the JavaScript data updates automatically.

In Vue 3, v-model is actually syntactic sugar for one-way data flow:

  • It passes a prop (modelValue).
  • It listens for an event (update:modelValue).

Example: Manual vs. Two-way

Technical Breakdown of v-model

When you use v-model on a custom component, Vue expands it under the hood to maintain one-way flow principles while giving you the ease of two-way binding.

Code Expanded Equivalent
<CustomInput v-model="email" /> <CustomInput :modelValue="email" @update:modelValue="email = $event" />

When to Use Which?
  • Use Two-way Binding (v-model): Inside forms and simple input components where the relationship between the UI and the variable is 1:1.
  • Use One-way Data Flow: For complex application architecture. If you find yourself passing data through many layers of components, stick to strict one-way flow (or a state management tool like Pinia) to keep the data path clear.

CSS Scoping in Single-File Components

In Vue, CSS Scoping ensures that the styles defined in a component do not "leak" out and affect the rest of the application. By default, CSS in a <style> block is global, but Vue provides built-in mechanisms to isolate styles to the current component.


Scoping Mechanisms
Feature Syntax Behavior
Global Style <style> Standard CSS; affects the entire app.
Scoped Style <style scoped> Limits styles to the current component using data-attributes.
CSS Modules <style module> Compiles classes into unique hashed strings (e.g., .title_hj3k).

1. Scoped CSS (scoped)

When you add the scoped attribute, Vue uses PostCSS to transform your CSS. It adds a unique attribute (like data-v-f3f3eg) to all elements in the component and appends that attribute to your CSS selectors.

Example:

Rendered Output:

2. Deep Selectors (:deep())

Sometimes you need to modify the style of a child component from a parent. Because of scoping, a standard selector won't reach inside the child. Use the :deep() pseudo-class to "pierce" the scope.


3. Slotted Selectors (:slotted())

By default, styles in a parent component do not affect content passed into a <slot>. To target slotted content specifically, use :slotted().


4. Dynamic CSS (v-bind in CSS)

Vue 3 allows you to link CSS values directly to your JavaScript state using the v-bind() function inside the <style> block. This is a game-changer for dynamic themes or UI elements.


Best Practices
  • Use Scoped by Default: Always start with <style scoped> to avoid naming collisions.
  • Avoid Deep Selectors for Logic: Only use :deep() for styling third-party libraries or shared UI components where you can't edit the source.
  • Use v-bind for Layouts: Instead of complex :style bindings in the template, use v-bind() in CSS to keep the template clean.

CSS Modules Overview

CSS Modules are an alternative to <style scoped> for styling components. While Scoped CSS uses data-attributes to isolate styles, CSS Modules transform your class names into unique hashes during the build process. This ensures that no two classes in your entire application can ever conflict, even if they share the same name.

In Vue, you enable this by adding the module attribute to your <style> block.


Scoped CSS vs. CSS Modules
Feature <style scoped> <style module>
Mechanism Adds data-v-xxxx attributes. Replaces class names with hashed strings.
Usage Standard HTML classes: class="title". JS Object mapping: :class="$style.title".
Specificity Increases slightly (due to attribute). No increase (remains a single class).
Flexibility Easier to use for beginners. Better for large-scale, complex projects.

How It Works

When you use <style module>, Vue exposes a computed property called $style to the component. This object contains the mapping between your "human-readable" class names and the "machine-hashed" versions.

1.Basic Implementation Example:
Rendered Output:

Advanced Usage
Named Modules

If you have multiple style blocks, you can name them to keep your styles organized. This is helpful for separating "layout" styles from "theme" styles.

Accessing in <script setup>

You can access the module classes inside your logic using the useCssModule hook. This is useful if you need to pass a class name to a third-party library or a child component as a string.


Why use CSS Modules?
  • Zero Conflict Guaranteed: Because every class is hashed, it is impossible for a style in Header.vue to accidentally overwrite a style in Footer.vue.
  • Explicit Mapping: It makes it very clear which classes are being applied to which elements through :class binding.
  • Performance: No runtime overhead for attribute matching; the browser just handles standard classes.

When to Choose Modules over Scoped?
  • Scoped: Best for most standard Vue applications where simplicity is key.
  • Modules: Best for Design Systems, component libraries, or very large enterprise applications where absolute isolation and programmatic access are required.

Vue Transitions and Animations Overview

Vue provides the <Transition> and <TransitionGroup> built-in components to handle enter/leave animations for elements or components. These components don't animate elements themselves; instead, they detect when an element is inserted or removed and apply specific CSS classes at the right moments.


How <Transition> Works

The most common use case is wrapping an element controlled by v-if or v-show. Vue automatically toggles six CSS classes during the transition lifecycle:

Class Name Description
v-enter-from Starting state for enter. Added before element is inserted.
v-enter-active Active state for enter. Applied during the entire animation.
v-enter-to Ending state for enter. Removed when animation finishes.
v-leave-from Starting state for leave. Applied when leave is triggered.
v-leave-active Active state for leave. Applied during the entire leaving phase.
v-leave-to Ending state for leave. Removed when animation finishes.

Basic Implementation
1. The Template

You can name your transition to customize the class prefix. If you name it fade, the classes become .fade-enter-active, etc.

2. The CSS

Key Features and Components
Component Purpose Key Feature
<Transition> Single element/component. Supports v-if, v-show, and dynamic components.
<TransitionGroup> List of elements (v-for). Supports FLIP animation for moving items in a list.
mode attribute Controls timing. out-in (wait for old to leave) or in-out.
JS Hooks Fine-grained control. @before-enter, @enter, @after-enter.

Transitioning Lists with <TransitionGroup>

Unlike <Transition>, <TransitionGroup> renders an actual DOM element (default is none, but can be specified with tag="ul"). It also requires every child to have a unique :key.

  • The Move Class: Use .list-move to apply transitions to items that are changing position (e.g., when an item is deleted and others slide into place).

JavaScript Hooks

If you want to use an animation library like GSAP or Anime.js, you can skip CSS classes and use JavaScript hooks instead:

Note: Setting :css="false" tells Vue to skip CSS detection, which improves performance for JS-only animations.

Testing Vue Components Overview

Testing in the Vue ecosystem is primarily handled by two tools: Vitest (the test runner) and Vue Test Utils (the library for mounting and interacting with components).

As of 2026, Vitest is the industry standard for Vue projects due to its speed and native integration with Vite.


The Core Toolset
Tool Role Description
Vitest The Engine Runs the tests, provides globals like describe, it, and expect.
Vue Test Utils (VTU) The Driver The official library that "mounts" a .vue component in a simulated browser environment.
Happy-dom / JSDOM The Environment A JavaScript implementation of the DOM so tests can run in Node.js.

Key Concepts: mount vs. shallowMount

When testing a component, you have two ways to render it:

  1. mount(): Renders the component and all of its children. Best for integration tests where you want to ensure components work together.
  2. shallowMount(): Renders the component but stubs out all children. Best for isolated unit tests to ensure the logic of a single component is correct without side effects from children.

A Basic Component Test

Suppose we have a Counter.vue component. Here is how we would test its functionality:


Common Testing Patterns
1. Testing Props

You can pass props directly during the mounting process to see if the component renders correctly.

2. Emitted Events

You can verify if a component correctly emitted an event back to its parent.

3. Testing Pinia and Router

When testing components that rely on global plugins, you must provide them in the global.plugins array.


Best Practices for Testing
  • Test Behavior, Not Implementation: Don't test private methods or internal state variables. Instead, test what the user sees (HTML) and how they interact (Events).
  • Use data-test attributes: Instead of selecting by CSS classes (which change often), use custom attributes like <button data-test="submit-btn">.
  • Async/Await: Always await any action that triggers a DOM update (like trigger() or setValue()) to ensure Vue has finished its rendering cycle before you make assertions.

Functional Components Overview

In Vue 3, a Functional Component is a component that has no internal state (no data or ref), no lifecycle hooks, and no instance (no this). It is essentially a plain JavaScript function that accepts props and context and returns a Virtual DOM node (VNode).


Functional vs. Stateful Components
Feature Stateful Component (.vue) Functional Component (Function)
State Can have ref, reactive. Stateless.
Lifecycle onMounted, onUpdated, etc. None.
Performance Standard (highly optimized). Slightly faster (zero instance overhead).
Instance Has a this or internal instance. No instance; pure function.
Complexity Best for most UI elements. Best for simple, repetitive wrappers.

Defining a Functional Component

In Vue 3, functional components are defined as simple functions. They are no longer defined via an object property { functional: true } like they were in Vue 2.

1. Using JavaScript/TypeScript

2. Using Single File Components (SFC)

You can still use the <template> block by adding the functional attribute, though this is less common in Vue 3 as the performance gap has significantly narrowed.


When to Use Functional Components?

While standard components are now fast enough that the difference is negligible for most apps, functional components are still useful for:

  • Higher-Order Components (HOCs): Creating components that wrap others to inject logic or styles.
  • Dynamic Layout Wrappers: Components that decide which tag to render (e.g., a SmartLink that chooses between an <a> and a <router-link>).
  • Recursive Trees: Rendering complex, nested structures (like file folders) where thousands of instances are created.

The "Context" Argument

The second argument in a functional component, context, provides three main properties:

  1. attrs: All attributes passed to the component that aren't defined as props.
  2. slots: The content passed into slots.
  3. emit: The ability to trigger events back to the parent.

Key Considerations
  • No <script setup>: You cannot use the <script setup> syntax for functional components; they are defined as standard functions.
  • Template Compilation: If you write them as functions, you must use the h() function (Render Function), which requires a deeper understanding of the Virtual DOM.

Production Optimization Overview

Optimizing a Vue application involves reducing the bundle size, improving load times, and ensuring the code runs as efficiently as possible in the browser. In modern Vue 3 development, most of this is handled by Vite (using Rollup under the hood), but understanding the underlying mechanisms allows for fine-tuning.


Core Optimization Techniques
Technique Tool / Method Benefit
Tree Shaking Rollup / ES Modules Removes unused code from dependencies.
Minification esbuild / Terser Shrinks file size by removing whitespace and renaming variables.
Code Splitting () => import() Loads code only when needed (Lazy Loading).
Asset Compression Gzip / Brotli Compresses files for faster transfer over the network.
Production Build npm run build Switches Vue into "Production Mode" (disables warnings/dev tools).

1. Tree Shaking

Tree shaking relies on Static Analysis of ES Modules (import and export). If you import a large library like lodash but only use one function, a tree-shaking bundler will "shake off" the unused functions, excluding them from the final bundle.

  • Vue-specific Tip: Vue 3 is designed to be highly tree-shakeable. If you don't use features like <Transition> or v-model, the code for those features is not included in your final JS file.

2. Minification & Mangling

Vite uses esbuild by default for minification because it is significantly faster than traditional tools.

  • Minification: Removes comments, line breaks, and extra spaces.
  • Mangling: Shortens variable names (e.g., const userAuthenticated = true becomes const a=true).

3. Dependency Optimization

Large dependencies are often the biggest cause of "bundle bloat".

  • Manual Chunking: You can tell Vite to split large libraries into their own files so they can be cached separately by the browser.
  • CDN Usage: For very large, rarely changing libraries (like a 3D engine), you might load them via a CDN rather than bundling them.

4. Reducing Feature Flags

Vue 3 includes code to support the Options API and Vue DevTools. If you are using only the Composition API in production, you can disable these flags to save a few kilobytes.


5. Image and Asset Optimization
  • WebP/Avif Conversion: Use modern formats for images.
  • SVG Bundling: Use tools like vite-svg-loader to inline icons, reducing HTTP requests.
  • Lazy Loading Images: Use the native <img loading="lazy"> or Vue-specific directives.

Summary: The "Production Mode" Difference

When you run npm run build, Vue automatically:

  1. Strips Dev Warnings: All those "Vue Warning" messages in your console are removed to save space and performance.
  2. Optimizes Templates: The compiler performs more aggressive "Static Hoisting" and "Patch Flag" insertions.
  3. Removes Debugging Code: Logic used only by the Vue DevTools is purged.

Vue DevTools Overview

Vue DevTools is the essential browser extension (available for Chrome, Firefox, and Edge) used for debugging and inspecting Vue.js applications in real-time. It acts as a "window" into the internal state of your app, allowing you to see things that are otherwise invisible in the standard browser console.

As of Vue 3, the extension has been completely rebuilt to support the Composition API, Pinia, and Vue Router integrations.


Core Features and Tabs
Tab / Feature Purpose Key Capability
Components Inspect the Virtual DOM tree. View and edit props, setup variables (ref, reactive), and computed values on the fly.
Timeline Performance and Event tracking. Record component renders, mouse events, and keyboard inputs to find "jank" or lag.
Pinia / Vuex State Management inspection. View the global state, time-travel through state changes, and manually trigger "Actions."
Routes Navigation history. See the current route, active params, and history of navigation guards.
Events Custom event tracking. Inspect $emit payloads sent from child to parent components.

Key Debugging Capabilities
1. Live State Editing

You don't need to refresh your code to see how a component behaves with different data. You can click on a ref value in the DevTools and manually change it. The UI will instantly react as if the change happened in your code.

2. Component Highlighting

Hovering over a component in the DevTools tree highlights the corresponding elements in the physical browser window. This is invaluable for locating specific components in complex, nested layouts.

3. "Open in Editor"

By configuring your local environment, you can click a button next to a component name in the DevTools, and your code editor (like VS Code) will automatically open that specific file.

4. Performance Profiling

The Timeline tab allows you to see exactly how long a component takes to "patch" the DOM. This helps identify "heavy" components that might be re-rendering too frequently.


The "New" Vite Plugin: Vue DevTools 7.0+

There is a newer version of Vue DevTools that runs inside your browser window as a Vite plugin, rather than just a browser extension.

  • Setup: npm add -D vite-plugin-vue-devtools
  • Advantage: It works across all browsers (including mobile via remote debugging) and provides a more integrated experience, including an Asset inspector and Module graph.

Security and Production

By default, Vue DevTools only works in Development Mode.

  • Production: The extension is disabled to prevent users from inspecting your app's internal logic or state.
  • Forcing Enablement: If you absolutely must use it in production (for debugging a live bug), you can set the __VUE_PROD_DEVTOOLS__ flag to true in your build configuration, though this is generally discouraged.

Summary of Benefits
  • Visualizes the Component Hierarchy.
  • Speeds up Debugging by exposing internal state.
  • Monitors Performance via the timeline.
  • Debugs Global State (Pinia) with time-traveling.

Overview of Scaling Vue Applications

As a Vue application grows from a simple project to an enterprise-level platform, the focus shifts from "making it work" to maintainability, performance, and developer experience. Scaling requires a combination of architectural discipline and the right tooling.


Core Principles for Large-Scale Vue
Category Best Practice Benefit
Architecture Use a Feature-based Folder Structure. Avoids "folder bloat" by grouping logic by business domain.
Logic Maximize Composables. Keeps components thin and promotes logic reuse across the app.
Type Safety Use TypeScript strictly. Prevents runtime errors and provides excellent IDE "Intellisense."
State Normalize Pinia Store structure. Prevents deeply nested, hard-to-track global state.
Performance Implement Async Components. Reduces the main bundle size through strategic code-splitting.

1. Feature-Based Folder Structure

In small apps, we often use components/, views/, and store/. In large apps, this leads to hundreds of files in one folder; instead, group by Domain:


2. Strict Component Design
  • Props vs. Store: Pass data via props for UI components (atoms/molecules). Use Pinia only for "Smart" components (pages/organisms) that truly need global state.
  • Controlled Components: Favor "Stateless" UI components that emit events rather than components that manage their own complex internal state.
  • Slots over Props: If a component needs to render complex HTML provided by the parent, use Slots instead of passing long strings or HTML through props.

3. Performance at Scale
  • ShallowRef: For large datasets (like a list of 1,000 objects from an API) that don't need deep reactivity, use shallowRef. This prevents Vue from making every nested property reactive, saving massive amounts of memory.
  • Component Teleportation: Use <Teleport> to move modals and popups to the bottom of the <body> to avoid CSS z-index and "overflow: hidden" conflicts in complex layouts.
  • Vite Plugins: Use unplugin-vue-components to auto-import components, reducing the boilerplate in your <script> blocks.

4. Error Handling & Monitoring
  • Global Error Handler: Use app.config.errorHandler to catch and log errors to a service like Sentry.
  • Boundary Components: Use the onErrorCaptured lifecycle hook in parent components to display "Fallback UI" if a specific feature crashes without breaking the whole app.

5. Consistency (The "Rulebook")
  • ESLint & Prettier: Strictly enforce a coding style (e.g., Vue's official "Essential" rules).
  • Component Library: Use a tool like Storybook to document and test UI components in isolation from the main app.

From The Same Category

Angular

Browse FAQ's

AngularJS

Browse FAQ's

React

Browse FAQ's

DocsAllOver

Where knowledge is just a click away ! DocsAllOver is a one-stop-shop for all your software programming needs, from beginner tutorials to advanced documentation

Get In Touch

We'd love to hear from you! Get in touch and let's collaborate on something great

Copyright copyright © Docsallover - Your One Shop Stop For Documentation