Vue.js Cheat Sheet
A quick reference to Vue.js directives, the Composition API, and single-file components for building reactive web interfaces.
App Setup & Composition API
Creating a Vue app and using reactive primitives in a component.
import { createApp } from 'vue'import App from './App.vue'createApp(App).mount('#app')// Composition API inside a component's setup()import { ref, computed, onMounted } from 'vue'export default { setup() { const count = ref(0) // reactive primitive, access via .value const doubled = computed(() => count.value * 2) function increment() { count.value++ } onMounted(() => console.log('component mounted')) return { count, doubled, increment } }}
Template Directives
Common directives for conditionals, loops, and binding.
<div v-if='isVisible'>Shown</div><div v-else>Hidden</div><li v-for='item in items' :key='item.id'>{{ item.name }}</li><img :src='imageUrl' :alt='altText' /><button @click='increment'>+1</button><input v-model='searchText' placeholder='Search' /><p v-show='isOnline'>Online</p>
Composition API Essentials
The core functions used to build reactive components.
- ref- creates a reactive reference wrapping a value; read/write it through .value
- reactive- creates a deeply reactive object; no .value needed to access its properties
- computed- derives a cached value that only recalculates when its dependencies change
- watch- explicitly observes one or more reactive sources and runs a callback on change
- watchEffect- runs a function immediately and re-runs it whenever any reactive value it reads changes
- onMounted- lifecycle hook that fires after the component has been mounted to the DOM
- onUnmounted- lifecycle hook that fires when the component is removed from the DOM
- provide / inject- pass data down the component tree without prop drilling through every level
Single File Component (script setup)
The modern SFC syntax using the <script setup> compiler sugar.
<script setup>import { ref } from 'vue'const count = ref(0)</script><template> <button @click='count++'>Count: {{ count }}</button></template><style scoped>button { padding: 8px 16px; }</style>
Custom Composable: useFetch
Extracting stateful async logic into a reusable composable function.
import { ref, watchEffect, toValue } from 'vue'export function useFetch(url) { const data = ref(null) const error = ref(null) const loading = ref(false) watchEffect(async () => { loading.value = true data.value = null error.value = null try { const target = toValue(url) // unwraps refs, getters, or plain values const res = await fetch(target) data.value = await res.json() } catch (e) { error.value = e } finally { loading.value = false } }) return { data, error, loading }}// usage: const { data, loading } = useFetch(() => `/api/users/${userId.value}`)
Pinia Store (Composition Style)
Defining and consuming a global store with state, getters, and actions.
import { defineStore } from 'pinia'import { ref, computed } from 'vue'export const useCartStore = defineStore('cart', () => { const items = ref([]) const total = computed(() => items.value.reduce((sum, i) => sum + i.price * i.qty, 0) ) function addItem(item) { items.value.push(item) } return { items, total, addItem }})// in a componentimport { useCartStore } from '@/stores/cart'import { storeToRefs } from 'pinia'const cart = useCartStore()const { total } = storeToRefs(cart) // keep reactivity when destructuring state
Advanced Reactivity APIs
Lower-level reactivity utilities for performance tuning and interop.
- shallowRef- creates a ref that is only reactive at the top level; avoids deep reactivity overhead for large objects you replace wholesale
- toRaw- returns the original, non-reactive object behind a reactive proxy, useful for passing data to non-Vue libraries
- markRaw- marks an object so Vue never converts it into a reactive proxy in the first place
- readonly- creates a read-only reactive proxy, throwing a warning on mutation attempts (useful for exposing store state safely)
- toRefs- converts a reactive object into an object of individual refs so its properties can be destructured without losing reactivity
- effectScope- groups multiple reactive effects (watchers, computeds) so they can all be disposed together, used internally by composables
- nextTick- returns a promise that resolves after the next DOM update cycle, for reading post-update DOM state
Typed defineProps/defineEmits & Scoped Slots
Generic-based prop/emit typing plus exposing data to parent-provided slot content.
<script setup lang="ts">interface Props { items: { id: number; name: string }[] title?: string}const props = withDefaults(defineProps<Props>(), { title: 'List' })const emit = defineEmits<{ select: [id: number]}>()</script><template> <h2>{{ title }}</h2> <ul> <li v-for="item in items" :key="item.id" @click="emit('select', item.id)"> <slot name="item" :item="item">{{ item.name }}</slot> </li> </ul></template><!-- parent usage --><!-- <ItemList :items="items"> <template #item="{ item }"> <strong>{{ item.name }}</strong> </template></ItemList> -->
Teleport & Suspense
Rendering content outside the component's DOM subtree and handling async setup() gracefully.
<!-- Teleport: render a modal at <body> level to escape overflow/z-index issues --><Teleport to="body"> <div v-if="showModal" class="modal">Modal content</div></Teleport><!-- Suspense: show a fallback while an async component's setup() resolves --><Suspense> <template #default> <AsyncUserProfile :id="userId" /> </template> <template #fallback> <p>Loading profile...</p> </template></Suspense><!-- AsyncUserProfile.vue can use top-level await in <script setup> --><!-- const user = await fetchUser(props.id) -->
Prefer <script setup> over the Options API for new components -- it compiles to less code and gives better TypeScript inference, but you still need to explicitly import ref, computed, and watch from vue.