Vue Cheat Sheet

By Syncfusion®, Inc. · Last updated

A quick reference for the whole Vue course: templates and directives, reactivity, rendering, events and forms, components, the Options API, composables, directives and plugins, routing, Pinia, HTTP, built-in components, transitions, rendering modes, testing, performance, errors and deployment.

What you will learn

  • Find the exact Vue syntax for a task in seconds
  • Jump to the lesson that explains each topic in full

How to Use This Cheat Sheet

  • This page is a quick reference for the whole course, in course order.
  • Each block shows the common patterns as short code you can copy.
  • Each block names the lesson that explains it in full.
  • Code samples follow the TypeScript / JavaScript picker in the top bar.

A Real-World Example

  • A developer is adding a booking form to Meera's site.
  • She forgot the exact defineModel() syntax and the .number modifier.
  • She finds both here in seconds, instead of reading two lessons again.

Start an App

Introduction to Vue

// main.ts
import { createApp } from "vue";
import App from "./App.vue";

createApp(App).mount("#app");
npm create vue@latest   # new project
npm install             # packages
npm run dev             # dev server with HMR
npm run build           # production files in dist/

Templates and Directives

Templates and Directives

<template>
  <p>{{ price * plates }}</p>                    <!-- one expression -->
  <img :src="photo" :alt="dish" />              <!-- v-bind shorthand -->
  <button :disabled="soldOut">Order</button>    <!-- false removes it -->
  <input v-bind="attrs" />                      <!-- many attributes -->
  <p v-html="trustedHtml"></p>                  <!-- only trusted HTML -->
  <p v-once>{{ firstSpecial }}</p>              <!-- render once -->
</template>
Directive partExample
Namev-on
Argument:submit
Dynamic argument:[eventName]
Modifier.prevent
Value="save"

Reactivity

Reactive State, Computed Properties and Watchers, Advanced Reactivity

<script setup lang="ts">
import { ref, reactive, computed, watch, watchEffect, nextTick, toRefs } from "vue";

const count = ref<number>(0);              // count.value in script
const order = reactive({ plates: 1 });     // no .value, do not destructure
const { plates } = toRefs(order);          // safe destructure
const double = computed(() => count.value * 2);

watch(count, (now, before) => console.log(before, "→", now), { immediate: true });
watch(() => order.plates, (p) => console.log("plates", p));
watchEffect(() => console.log("count is", count.value));

async function add(): Promise<void> {
  count.value++;
  await nextTick();                        // DOM is updated now
}
</script>
NeedUse
A value from statecomputed
A job when state changeswatch / watchEffect
Big data replaced as a wholeshallowRef + triggerRef
Read-only viewreadonly()
A debounced refcustomRef()

Dynamic and List Rendering

Dynamic Rendering, List Rendering

<template>
  <p :class="{ active: isOn, 'sold-out': soldOut }" :style="{ fontSize: size + 'px' }">Dosa</p>
  <p v-if="hour < 11">Breakfast</p>
  <p v-else-if="hour < 16">Lunch</p>
  <p v-else>Dinner</p>
  <ul v-show="open">
    <li v-for="(dish, i) in shown" :key="dish.id">{{ i + 1 }}. {{ dish.name }}</li>
  </ul>
  <span v-for="n in 3" :key="n">{{ n }}</span>   <!-- 1, 2, 3 -->
</template>
  • Filter and sort in a computed, never v-if with v-for on one element.
  • filter and map return new arrays: assign them.

Events and Forms

Events and Forms

<template>
  <button @click="add(2, $event)">Add 2</button>
  <input @keyup.enter="save" @keyup.esc="clear" />
  <div @click="open"><button @click.stop="like">Like</button></div>
  <form @submit.prevent="submit">
    <input v-model.trim="name" :aria-invalid="!!error" :aria-describedby="errorId" />
    <input v-model.number="guests" type="number" />
    <input type="checkbox" v-model="extras" value="chutney" />
    <select v-model="time"><option>19:00</option></select>
    <p :id="errorId">{{ error }}</p>
    <button :disabled="!!error">Book</button>
  </form>
</template>

Components

Components and Single-File Components, Props and Events, Slots, Attributes and Provide/Inject

<script setup lang="ts">
const props = defineProps<{ name: string; price?: number }>();
const emit = defineEmits<{ add: [name: string] }>();
const qty = defineModel<number>({ default: 1 });
</script>

<template>
  <div class="card">
    <slot name="header" />
    <slot :dish="props.name">{{ props.name }}</slot>
    <button @click="emit('add', props.name)">Add</button>
  </div>
</template>

<style scoped>
.card :deep(.price) { color: crimson; }
</style>
<template>
  <DishCard name="Idli" :price="50" v-model="plates" @add="cart.push($event)">
    <template #header><h3>Breakfast</h3></template>
    <template #default="{ dish }">⭐ {{ dish }}</template>
  </DishCard>
</template>
  • Props down, events up. Never change a prop.
  • Runtime props in JavaScript: defineProps({ name: { type: String, required: true } }).

Attributes, Provide/Inject and Lifecycle

Slots, Attributes and Provide/Inject, Lifecycle and Template Refs

defineOptions({ inheritAttrs: false });          // then v-bind="$attrs"

provide(cartKey, cart);                          // ancestor
const cart = inject(cartKey, ref([]));           // any descendant

onMounted(() => { /* DOM ready: start timers, listeners */ });
onUnmounted(() => { /* clean everything up */ });

const box = useTemplateRef<HTMLInputElement>("box");   // ref="box"
defineExpose({ reset });                         // what a parent ref sees

Options API

Options API

export default defineComponent({
  props: { price: { type: Number, required: true } },
  emits: ["add"],
  data() { return { plates: 1 }; },
  computed: { total(): number { return this.price * this.plates; } },
  watch: { plates(now: number) { console.log(now); } },
  methods: { addPlate() { this.plates++; } },
  mounted() { console.log("on the page"); },
});

Reuse: Composables, Directives and Plugins

Composables, Directives and Plugins

// composables/useCounter.ts
export function useCounter(start: MaybeRefOrGetter<number> = 0) {
  const count = ref(toValue(start));
  const add = () => count.value++;
  return { count, add };                         // refs: safe to destructure
}

// a directive (in <script setup>, vFocus = v-focus)
const vFocus: Directive<HTMLElement> = { mounted: (el) => el.focus() };

// a plugin
export const kitchenPlugin = {
  install(app: App, options: { shop: string }) {
    app.provide("shop", options.shop);
    app.directive("focus", vFocus);
  },
};

TypeScript

TypeScript with Vue

const props = defineProps<{ dish: Dish; plates?: number }>();
const emit = defineEmits<{ add: [name: string] }>();
const qty = defineModel<number>({ default: 1 });
const chosen = ref<Dish | null>(null);
const box = useTemplateRef<HTMLInputElement>("box");
export const themeKey: InjectionKey<Ref<Theme>> = Symbol("theme");
// <script setup lang="ts" generic="T extends { id: number }">
// npx vue-tsc --noEmit    (Vite does not check types)

Routing

Vue Router Basics, Navigation Guards and Advanced Routing

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: "/", component: HomePage },
    { path: "/dish/:id", name: "dish", component: DishPage, props: true },
    { path: "/admin", component: () => import("./views/Admin.vue"), meta: { requiresAuth: true } },
    { path: "/:pathMatch(.*)*", component: NotFound },
  ],
});

router.beforeEach((to) => {
  if (to.meta.requiresAuth && !loggedIn.value) return { path: "/login", query: { redirect: to.fullPath } };
});
<template>
  <RouterLink :to="{ name: 'dish', params: { id: 2 } }">Dish 2</RouterLink>
  <RouterView />
</template>
  • useRoute() reads params and query. useRouter() does push, replace and go.

Pinia

State Management with Pinia

export const useCartStore = defineStore("cart", () => {
  const items = ref<string[]>([]);
  const count = computed(() => items.value.length);
  function add(dish: string): void { items.value.push(dish); }
  return { items, count, add };
});

const cart = useCartStore();
const { count } = storeToRefs(cart);             // state and getters
const { add } = cart;                            // actions directly

HTTP

HTTP Requests, Authentication and Real-Time Data

const res = await fetch(`${import.meta.env.VITE_API_URL}/dishes`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "Pongal" }),
  signal: controller.signal,                     // AbortController
});
if (!res.ok) throw new Error(`Request failed (${res.status})`);
const dish = await res.json();

// auth: send the token on every request, refresh once on 401
api.interceptors.request.use((c) => (c.headers.set("Authorization", `Bearer ${auth.token}`), c));

// live data: close on unmount
const socket = new WebSocket("wss://api.example.com/live");
onUnmounted(() => socket.close());

Advanced Components and Transitions

Dynamic and Built-In Components, Transitions and Animations, Render Functions and Component Patterns

<template>
  <KeepAlive><component :is="current" /></KeepAlive>
  <Teleport to="body"><div v-if="open" class="modal" role="dialog">…</div></Teleport>
  <Transition name="fade" mode="out-in"><p :key="text">{{ text }}</p></Transition>
  <TransitionGroup name="list" tag="ul"><li v-for="o in orders" :key="o.id">{{ o.dish }}</li></TransitionGroup>
</template>
const Chart = defineAsyncComponent(() => import("./Chart.vue"));
const render = () => h("button", { onClick: add }, "Add");

Rendering Modes, Testing and Production

How Vue Renders, Server and Static Rendering, Nuxt: Full-Stack Vue, Testing Vue Apps, Performance, Errors, Security and Deployment, Capstone: Build Meera's Kitchen

const html = await renderToString(createSSRApp(App));     // server
createSSRApp(App).mount("#app");                          // hydrate

it("adds a dish", async () => {                           // Vitest + VTU
  const wrapper = mount(DishCard, { props: { name: "Idli" } });
  await wrapper.find("button").trigger("click");
  expect(wrapper.emitted("add")).toEqual([["Idli"]]);
});

app.config.errorHandler = (err) => report(err);           // global errors
onErrorCaptured(() => { failed.value = true; return false; });
ModeHTML madeGood for
CSRIn the browserApps behind a login
SSROn the server, per requestFresh, shareable pages
SSR + SWR/ISROn the server, then cachedMenus, product pages
SSGAt build timeDocs, blogs, marketing
HybridPer route (route rules)Most real sites

Nuxt

Nuxt: Full-Stack Vue

// app/pages/dish/[id].vue → /dish/:id
const { data: dish, status } = await useFetch(`/api/dishes/${useRoute().params.id}`);
useSeoMeta({ title: () => `${dish.value?.name} | Meera's Kitchen` });
definePageMeta({ layout: "default", middleware: "auth" });

// server/api/dishes/[id].get.ts
export default defineEventHandler((event) => findDish(Number(getRouterParam(event, "id"))));

// nuxt.config.ts
export default defineNuxtConfig({ routeRules: { "/": { prerender: true }, "/menu": { swr: 60 } } });

Stuck on a pattern? Each heading above names the lesson that explains it with runnable boxes and exercises.

TL;DR

  • Start = createApp(App).mount("#app"), npm create vue@latest.
  • State = ref, reactive, computed, watch.
  • Templates = {{ }}, :attr, @event, v-if, v-for + :key, v-model.
  • Components = defineProps, defineEmits, defineModel, slots.
  • Reuse = composables, directives, plugins.
  • App-wide = Vue Router and Pinia.
  • Production = tests, performance, error handling, safe deployment.

Common mistakes

MistakeWrong ideaCorrect ideaWhat goes wrong
No .value in the scriptRefs work like plain variablescount.value++Nothing updates
Destructuring reactive or a storeValues stay linkedtoRefs / storeToRefsFrozen values
Index as :keyPositions are namesUse an idState jumps between rows
Changing a propProps are localEmit an event or copy itWarning and overwritten data
v-html with user textIt is just formatting{{ }}XSS
Secrets in VITE_ variables.env is privateKeep them on the serverAnyone can read them

Check Yourself

What to Remember

  • State: ref first, computed for values, watch for jobs.
  • Templates: : binds, @ listens, v-model does both, :key on every list item.
  • Components: props down, events up, slots for content, composables for logic.
  • Apps: Vue Router for pages, Pinia for shared state, a service module for HTTP.
  • Production: test, measure, handle errors kindly, keep secrets on the server.