Vue.js API Reference & Cheatsheet
Vue.js is a progressive JavaScript framework — this reference covers every directive, API, lifecycle hook, and built-in component you need for production Vue 3 apps.
What You’ll Learn
- All Vue directives with shorthands and modifiers
- Options API vs Composition API side-by-side
- Built-in components (Transition, KeepAlive, Teleport, Suspense)
- Pinia store setup and Vue Router configuration
- Template refs, render functions, and custom directives
- Global API and error handling patterns
Why This Reference Matters
When you’re building a Vue app, you don’t want to dig through 10 browser tabs to remember how v-model.lazy or onErrorCaptured works. This reference is your single source of truth — everything in one place.
Security note: Understanding Reference helps build more secure applications — a core principle at DodaTech, where tools like Durga Antivirus Pro and Doda Browser rely on solid implementation practices.
At DodaTech, our teams use this exact reference when building dashboard panels for Durga Antivirus Pro, file management views in DodaZIP, and settings pages in Doda Browser. Having a consolidated API reference speeds up development and reduces bugs.
Vue Curriculum — Where Reference Fits
flowchart LR
A[Vue Basics] --> B[Vue Components]
B --> C[Vue Router]
C --> D[Vue Advanced]
D --> E[Vue Reference]
E:::current
classDef current fill:#42b883,color:#fff,stroke:#3aa876,stroke-width:2px
Installation
npm create vite@latest my-app -- --template vue
cd my-app && npm install && npm run dev
npm install vue-router@4 piniaDirectives
| Directive | Shorthand | Purpose |
|---|---|---|
v-bind | : | Bind attribute to expression |
v-model | — | Two-way data binding |
v-if | — | Conditional render (remove/add DOM) |
v-else-if | — | Else-if condition |
v-else | — | Else condition |
v-show | — | Toggle CSS display |
v-for | — | List rendering |
v-on | @ | Event binding |
v-once | — | Render once |
v-memo | — | Memoize template fragment |
v-cloak | — | Hide until compiled |
v-pre | — | Skip compilation |
v-html | — | Raw HTML (XSS risk) |
v-text | — | Text content |
v-slot | # | Named/scoped slots |
Directive Modifiers
@click.stop <!-- stopPropagation — stops event from bubbling up -->
@click.prevent <!-- preventDefault — prevents form submission, etc. -->
@click.once <!-- fire once — event listener removed after first click -->
@keyup.enter <!-- key alias — fires only on Enter key -->
@keyup.ctrl.enter <!-- modifier + key — Ctrl+Enter combination -->
v-model.lazy <!-- sync on change instead of keystroke -->
v-model.number <!-- coerce input to number type -->
v-model.trim <!-- trim leading/trailing whitespace -->Options API
export default {
name: "ComponentName",
components: {}, // Local component registration
props: { // Props: parent → child data
title: String,
count: { type: Number, default: 0 }
},
emits: ["update", "delete"], // Declared events the component fires
data() { return { msg: "Hello" }; }, // Reactive state (must be function)
computed: { // Cached derived values
reversed() { return this.msg.split("").reverse().join(""); }
},
watch: { // Side effects on data changes
count(n, o) { /* n = new value, o = old value */ }
},
methods: { // Functions attached to the component
handleClick() { this.count++; }
},
// Lifecycle — runs in this order:
beforeCreate() {}, // Instance initialized, nothing reactive yet
created() {}, // Reactive data ready, no DOM
beforeMount() {}, // About to render
mounted() {}, // DOM in page — safe for API calls
beforeUpdate() {}, // Data changed, about to re-render
updated() {}, // DOM re-rendered
beforeUnmount() {}, // About to destroy component
unmounted() {}, // Cleanup timers, listeners
errorCaptured(err, instance, info) {}, // Catches child errors
};Composition API (<script setup>)
<script setup>
// All imports are available directly — no export default needed
import { ref, reactive, computed, watch, onMounted, provide, inject, nextTick } from "vue";
const count = ref(0); // ref() wraps any value, use .value in script
const state = reactive({ key: "value" }); // reactive() for objects, no .value
const double = computed(() => count.value * 2); // Computed: caches until deps change
watch(count, (n, o) => {}); // Watcher: runs function on change
onMounted(() => {}); // Lifecycle: onMounted, onUnmounted, etc.
provide("key", value); // Provide data to all descendants
const val = inject("key", "default"); // Inject data from ancestor
await nextTick(); // Wait for DOM update after state change
// Async setup — works inside Suspense
const data = await fetch("/api/data").then(r => r.json());
</script>Ref vs Reactive
const a = ref(0); // primitive → a.value to read/write
const b = ref({}); // object → b.value.key
const c = reactive({}); // object → c.key (no .value)
Built-in Components
| Component | Purpose | When to Use |
|---|---|---|
<component :is="..." /> | Dynamic component vending machine | Tab switching |
<slot /> | Content outlet | Layout components |
<Transition> | Animate enter/leave | Single element animations |
<TransitionGroup> | Animate list items | List reorder/add/remove |
<KeepAlive> | Cache dynamic components | Preserve form state across tabs |
<Teleport to="..."> | Render elsewhere in DOM | Modals, tooltips |
<Suspense> | Handle async deps | Loading states for async components |
<RouterLink> | Navigation link | SPA routing |
<RouterView> | Route outlet | Where matched route renders |
Lifecycle Hooks
Options API Composition API
─────────────────────────────────────
beforeCreate setup() ← component initialized
created setup() ← reactive state ready
beforeMount onBeforeMount ← about to render
mounted onMounted ← DOM is in page ✅ fetch data here
beforeUpdate onBeforeUpdate ← data changed, re-render pending
updated onUpdated ← DOM re-rendered
beforeUnmount onBeforeUnmount ← about to destroy
unmounted onUnmounted ← cleanup timers/listeners
errorCaptured onErrorCaptured ← catch child errors
activated onActivated ← KeepAlive — component re-activated
deactivated onDeactivated ← KeepAlive — component deactivatedVue Router
import { createRouter, createWebHistory } from "vue-router";
const router = createRouter({
history: createWebHistory(), // Clean URLs without #
routes: [
{ path: "/", component: Home },
{ path: "/:pathMatch(.*)*", component: NotFound } // Catch-all 404
],
scrollBehavior() { return { top: 0 }; } // Scroll to top on navigation
});
// In component:
this.$router.push("/path"); // Navigate (adds history entry)
this.$router.replace("/path"); // Navigate (replaces current entry)
this.$router.go(-1); // Back one step
this.$route.params.id; // Route parameter
this.$route.query.search; // Query string (?search=...)
Navigation Guards
router.beforeEach((to, from) => {}); // Global — runs on every route
router.afterEach((to, from) => {}); // Global — runs after navigation
// Per-route: beforeEnter in route config
// In-component: beforeRouteEnter, beforeRouteUpdate, beforeRouteLeave
Pinia
import { defineStore } from "pinia";
import { ref, computed } from "vue";
export const useStore = defineStore("name", () => {
const state = ref(initialValue);
const getter = computed(() => state.value * 2);
function action() { state.value++; }
return { state, getter, action };
});
// In component:
const store = useStore();
store.state; // read
store.state++; // mutate (allowed directly in Pinia)
store.action(); // call action
Template Refs
<input ref="input" />
<p v-for="item in list" :ref="setItemRef" />// Options API
this.$refs.input.focus();
// Composition API
const input = ref(null); // ref name must match template ref name
onMounted(() => input.value?.focus());Class & Style Bindings
<div :class="{ active: isActive, 'text-danger': hasError }" />
<div :class="[baseClass, activeClass]" />
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }" />
<div :style="[baseStyles, overrides]" />Render Function
import { h } from "vue";
h("div", { class: "box", style: { color: "red" } }, [
h("h1", "Title"),
h("p", "Content")
]);Custom Directive
app.directive("highlight", {
mounted(el, binding) { el.style.background = binding.value; },
updated(el, binding) { el.style.background = binding.value; }
});Global API
const app = createApp(App);
app.component("name", Comp); // Register global component
app.directive("name", directive); // Register global directive
app.use(plugin); // Install plugin (router, pinia)
app.provide("key", value); // Provide data globally
app.config.errorHandler = (err, instance, info) => {}; // Global error handler
app.config.globalProperties.$api = axios; // Make available in all components
Common Mistakes
1. Using v-html with user input
v-html renders raw HTML. If the content comes from users, attackers can inject <script> tags. Only use v-html with trusted content from your server.
2. Forgetting that data must be a function
// ❌ Bad — all instances share the same state
data: { count: 0 }
// ✅ Correct — each instance gets its own copy
data() { return { count: 0 }; }3. Confusing Options API and Composition API lifecycle names
mounted() in Options becomes onMounted() in Composition API. The on prefix is easy to forget.
4. Mutating Pinia state outside of actions
Pinia allows direct mutations in templates, but for complex logic always use actions — it makes debugging far easier when you can trace who changed what.
5. Not handling NavigationDuplicated errors
// router.push throws if you navigate to the current route
try {
await router.push("/same-page");
} catch (e) {
if (e.name !== "NavigationDuplicated") throw e;
}6. Forgetting :key with v-for in <TransitionGroup>
Without unique keys, Vue can’t track which items entered, left, or moved — animations break silently.
Practice Questions
1. What’s the shorthand for v-bind and v-on?
v-bind → :, v-on → @. Example: :src="url" and @click="handler".
2. How do you make a route parameter available as a component prop?
Set props: true in the route definition. The param (e.g., :id) becomes a prop on the component.
3. What’s the difference between mounted (Options) and onMounted (Composition)?
They do the same thing but have different names. Options uses mounted(), Composition uses onMounted(() => {}).
4. When would you use shallowRef instead of ref?
When you have large data that doesn’t need deep reactivity — like a static array of thousands of items. shallowRef only tracks .value assignment, not nested changes.
5. How do you catch errors in child components?
Use errorCaptured (Options) or onErrorCaptured (Composition). Return false to prevent the error from propagating upward.
Challenge: Open your browser console on any Vue app and inspect __vue_app__ on the root element. Explore the component tree, reactive state, and available methods. This is a powerful debugging technique.
FAQ
Try It Yourself
Copy this into a new HTML file and open it in your browser:
<!DOCTYPE html>
<html>
<head>
<title>Vue Reference Sandbox</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 40px auto; padding: 0 20px; }
.demo-box { border: 2px dashed #42b883; padding: 16px; border-radius: 8px; margin: 12px 0; }
input, button { padding: 8px; margin: 4px; border: 1px solid #ddd; border-radius: 4px; }
button { background: #42b883; color: white; cursor: pointer; }
.active { background: #e8f5e9; }
</style>
</head>
<body>
<div id="app">
<h1>Vue Reference Playground</h1>
<div class="demo-box">
<h3>v-model + computed</h3>
<input v-model="name" placeholder="Enter name">
<p>Uppercase: <strong>{{ upperName }}</strong></p>
</div>
<div class="demo-box">
<h3>v-if / v-show</h3>
<button @click="show = !show">Toggle</button>
<p v-if="show">v-if: I appear/disappear from DOM</p>
<p v-show="show">v-show: I'm hidden with CSS</p>
</div>
<div class="demo-box">
<h3>v-for with :key</h3>
<input v-model="newItem" @keyup.enter="addItem" placeholder="Add item">
<button @click="addItem">Add</button>
<ul>
<li v-for="(item, i) in items" :key="i">
{{ item }} <button @click="items.splice(i, 1)">✕</button>
</li>
</ul>
</div>
</div>
<script>
const { createApp, ref, computed } = Vue;
createApp({
setup() {
const name = ref("Vue");
const upperName = computed(() => name.value.toUpperCase());
const show = ref(true);
const items = ref(["Directive", "Component", "Reactivity"]);
const newItem = ref("");
function addItem() {
if (newItem.value.trim()) {
items.value.push(newItem.value.trim());
newItem.value = "";
}
}
return { name, upperName, show, items, newItem, addItem };
}
}).mount("#app");
</script>
</body>
</html>What to try: Type in the input and watch the uppercase version update live. Toggle the visibility buttons. Add and remove items from the list. All these use core Vue directives you’ve learned.
What’s Next
| Resource | Description |
|---|---|
| https://tutorials.dodatech.com/frameworks/vue/vue-advanced/ | Composition API, Pinia, advanced patterns |
| JavaScript | Master modern JavaScript fundamentals |
| TypeScript | Add type safety to your Vue apps |
| Node.js | Build backends for your Vue SPAs |
| React | Compare Vue with React for your next project |
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro