Index of every page on this site: llms.txt
All skills
antfu avatar

/vue

@7de210b official
by Anthony Fuantfu/skills6k stars
342
Run it yourself

Vue 3 Composition API, script setup macros, reactivity system, and built-in components. Use when writing Vue SFCs, defineProps/defineEmits/defineModel, watchers, or using Transition/Teleport/Suspense/KeepAlive.

Use this Skill: https://skilld.dev/gh/antfu/skills/vue

Nothing lands on disk. Nothing to clean up.

Fork this Skill

Edit a local copy. It keeps the author and licence.

referencescore-new-apis.md

≈1.4k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Reactivity, Lifecycle & Composables

Reactivity

ref vs shallowRef

import { ref, shallowRef } from 'vue'

// ref - deep reactivity (tracks nested changes)
const user = ref({ name: 'John', profile: { age: 30 } })
user.value.profile.age = 31  // Triggers reactivity

// shallowRef - only .value assignment triggers reactivity (better performance)
const data = shallowRef({ items: [] })
data.value.items.push('new')  // Does NOT trigger reactivity
data.value = { items: ['new'] }  // Triggers reactivity

Prefer shallowRef for large data structures or when deep reactivity is unnecessary.

computed

import { ref, computed } from 'vue'

const count = ref(0)

// Read-only computed
const doubled = computed(() => count.value * 2)

// Writable computed
const plusOne = computed({
  get: () => count.value + 1,
  set: (val) => { count.value = val - 1 }
})

reactive & readonly

import { reactive, readonly } from 'vue'

const state = reactive({ count: 0, nested: { value: 1 } })
state.count++  // Reactive

const readonlyState = readonly(state)
readonlyState.count++  // Warning, mutation blocked

Note: reactive() loses reactivity on destructuring. Use ref() or toRefs().

Inspecting reactive values

import { isRef, isReactive, isReadonly, isProxy, isShallow, unref, toRaw } from 'vue'

isShallow(shallowRef(0))   // true, also true for shallowReactive/shallowReadonly
isShallow(ref(0))          // false

isShallow() reports whether a proxy was created with shallowRef, shallowReactive(), or shallowReadonly().

Watchers

watch

import { ref, watch } from 'vue'

const count = ref(0)

// Watch single ref
watch(count, (newVal, oldVal) => {
  console.log(`Changed from ${oldVal} to ${newVal}`)
})

// Watch getter
watch(
  () => props.id,
  (id) => fetchData(id),
  { immediate: true }
)

// Watch multiple sources
watch([firstName, lastName], ([first, last]) => {
  fullName.value = `${first} ${last}`
})

// Deep watch with depth limit (Vue 3.5+)
watch(state, callback, { deep: 2 })

// Once (Vue 3.4+)
watch(source, callback, { once: true })

watchEffect

Runs immediately and auto-tracks dependencies.

import { ref, watchEffect, onWatcherCleanup } from 'vue'

const id = ref(1)

watchEffect(async () => {
  const controller = new AbortController()
  
  // Cleanup on re-run or unmount (Vue 3.5+)
  onWatcherCleanup(() => controller.abort())
  
  const res = await fetch(`/api/${id.value}`, { signal: controller.signal })
  data.value = await res.json()
})

// Pause/resume (Vue 3.5+)
const { pause, resume, stop } = watchEffect(() => {})
pause()
resume()
stop()

Flush Timing

// 'pre' (default) - before component update
// 'post' - after component update (access updated DOM)
// 'sync' - immediate, use with caution

watch(source, callback, { flush: 'post' })
watchPostEffect(() => {})  // Alias for flush: 'post'

Lifecycle Hooks

import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured,
  onActivated,      // KeepAlive
  onDeactivated,    // KeepAlive
  onServerPrefetch  // SSR only
} from 'vue'

onMounted(() => {
  console.log('DOM is ready')
})

onUnmounted(() => {
  // Cleanup timers, listeners, etc.
})

// Error boundary
onErrorCaptured((err, instance, info) => {
  console.error(err)
  return false  // Stop propagation
})

Effect Scope

Group reactive effects for batch disposal.

import { effectScope, onScopeDispose } from 'vue'

const scope = effectScope()

scope.run(() => {
  const count = ref(0)
  const doubled = computed(() => count.value * 2)
  
  watch(count, () => console.log(count.value))
  
  // Cleanup when scope stops
  onScopeDispose(() => {
    console.log('Scope disposed')
  })
})

// Dispose all effects
scope.stop()

Composables

Composables are functions that encapsulate stateful logic using Composition API.

Naming Convention

  • Start with use: useMouse, useFetch, useCounter

Pattern

// composables/useMouse.ts
import { ref, onMounted, onUnmounted } from 'vue'

export function useMouse() {
  const x = ref(0)
  const y = ref(0)

  const update = (e: MouseEvent) => {
    x.value = e.pageX
    y.value = e.pageY
  }

  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))

  return { x, y }
}

Accept Reactive Input

Use toValue() (Vue 3.3+) to normalize refs, getters, or plain values.

import { ref, watchEffect, toValue, type MaybeRefOrGetter } from 'vue'

export function useFetch(url: MaybeRefOrGetter<string>) {
  const data = ref(null)
  const error = ref(null)

  watchEffect(async () => {
    data.value = null
    error.value = null
    
    try {
      const res = await fetch(toValue(url))
      data.value = await res.json()
    } catch (e) {
      error.value = e
    }
  })

  return { data, error }
}

// Usage - all work:
useFetch('/api/users')
useFetch(urlRef)
useFetch(() => `/api/users/${props.id}`)

Return Refs (Not Reactive)

Always return plain object with refs for destructuring compatibility.

// Good - preserves reactivity when destructured
return { x, y }

// Bad - loses reactivity when destructured
return reactive({ x, y })
<!-- Source references: - https://vuejs.org/api/reactivity-core.html - https://vuejs.org/api/reactivity-advanced.html - https://vuejs.org/api/composition-api-lifecycle.html - https://vuejs.org/guide/reusability/composables.html -->

Source: SKILL.md on GitHub

No rule matched.

skilld matched fixed text patterns in SKILL.md and file names. Patterns miss obfuscated code.

skilld run checks every file with the same patterns. It asks for approval before it loads a Skill with a behavior marked Needs approval.

No alerts1mo5 checks · Risk SAFE
  • Gen Agent Trust Hub1mo

    The skill provides comprehensive guidelines and references for Vue 3 Composition API and <script setup>. It contains standard code examples and documentation from reputable sources. No security risks were identified.

  • Socket1mo

    No alerts

  • Snyk1mo

    Risk: LOW · No issues

  • Runlayer8mo

    1/5 files flagged

  • ZeroLeaks6mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 7de210b. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last week.

Activeupdated last month
Other metadata
metadata
{
  "author": "Anthony Fu",
  "version": "2026.9.25",
  "source": "Generated from https://github.com/vuejs/docs, scripts at https://github.com/antfu/skills"
}
  • Vue
  • TypeScript
  • vue3
  • composition-api
  • script-setup
  • reactivity
  • components
  • sfc

README badge

README badge for antfu/skills/vue

Provides Vue 3 Composition API patterns, script setup macros (defineProps, defineEmits, defineModel), reactivity utilities (ref, computed, watch), and built-in components (Transition, Teleport, Suspense, KeepAlive). Use when writing Vue SFCs with TypeScript and <script setup> syntax.

Generated from the current SKILL.md.

Does this skill cover Vue 2 or Vue 3?
This skill is based on Vue 3.5 and uses the Composition API exclusively. It does not cover Vue 2 or the Options API.
Should I use script setup or the traditional script block?
Always use `<script setup lang="ts">`. The skill discourages the traditional `<script>` block in favor of the more concise setup macro syntax.
Does this skill cover advanced patterns like Transition and Suspense?
Yes. The skill includes Vue's built-in components (Transition, Teleport, Suspense, KeepAlive) and directives like v-memo and custom directives.
When should I use shallowRef instead of ref?
Use shallowRef when deep reactivity is not needed, as it offers better performance than ref for large objects or arrays.
Does this skill recommend TypeScript?
Yes. The skill prefers TypeScript over JavaScript and all examples use `lang="ts"`.

Generated from the current SKILL.md. These answers refresh after source changes.