Vue
Anthony FuCommunityCreated by Anthony Fu
- Skill
- Tool integration
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured reference for building modern Vue 3 applications. It emphasizes the use of the Composition API and script setup syntax, offering guidance on reactivity primitives, lifecycle hooks, and built-in components. It covers essential patterns for managing component state, side effects, and DOM interactions, ensuring developers follow current best practices for performance and maintainability.
What it does
- Provides syntax patterns for script setup macros like defineProps, defineEmits, and defineModel.
- Explains the reactivity system including ref, shallowRef, computed, and watch.
- Details the usage of built-in components such as Transition, Teleport, Suspense, and KeepAlive.
- Outlines lifecycle hooks and their appropriate use cases within components.
- Offers guidance on effect scopes and composable patterns for managing reactive state.
- Includes quick reference templates for standard component structures.
When to use it
- When developing Vue 3 single-file components using the Composition API.
- When implementing complex reactivity or state management within a component.
- When handling component animations, portal rendering, or async loading states.
- When optimizing component performance using shallow reactivity or specific lifecycle management.
- When standardizing code structure across a Vue project.
Advantages
- Promotes consistent use of the modern Composition API and TypeScript.
- Provides clear performance optimization strategies like shallowRef.
- Simplifies complex tasks like DOM teleportation and async component handling.
- Encourages clean code through standardized script setup macros.
- Offers a centralized reference for Vue 3.5+ features.
Usage examples
- “How do I define props and emits in a Vue 3 script setup component?”
- The agent provides a code snippet using defineProps and defineEmits within a script setup block, demonstrating type-safe property and event definitions.
- “Show me how to use Teleport to render a modal in the body.”
- The agent generates a template example using the Teleport component with the to=body attribute to move content to the document root.
- “What is the difference between ref and shallowRef?”
- The agent explains that ref provides deep reactivity while shallowRef only tracks changes to the .value assignment, recommending shallowRef for performance optimization.
- “How can I watch a prop for changes in Vue 3?”
- The agent provides a watch function example that monitors a getter for the specific prop, including configuration options like immediate execution.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/antfu/vue/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip vue.zip -d .agents/skills
Documentation by Anthony Fu
Vue
Based on Vue 3.5, generated at 2026-09-25. Always use Composition API with
<script setup lang="ts">.
Preferences
Prefer TypeScript over JavaScript
Prefer
<script setup lang="ts">over<script>For performance, prefer
shallowRefoverrefif deep reactivity is not neededAlways use Composition API over Options API
Discourage using Reactive Props Destructure
Core
| Topic | Description | Reference |
|---|---|---|
| Script Setup & Macros | <script setup>, defineProps, defineEmits, defineModel, defineExpose, defineOptions, defineSlots, generics | script-setup-macros |
| Reactivity & Lifecycle | ref, shallowRef, computed, watch, watchEffect, effectScope, lifecycle hooks, composables | core-new-apis |
Features
| Topic | Description | Reference |
|---|---|---|
| Built-in Components & Directives | Transition, Teleport, Suspense, KeepAlive, v-memo, custom directives | advanced-patterns |
Quick Reference
Component Template
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
const props = defineProps<{
title: string
count?: number
}>()
const emit = defineEmits<{
update: [value: string]
}>()
const model = defineModel<string>()
const doubled = computed(() => (props.count ?? 0) * 2)
watch(() => props.title, (newVal) => {
console.log('Title changed:', newVal)
})
onMounted(() => {
console.log('Component mounted')
})
</script>
<template>
<div>{{ title }} - {{ doubled }}</div>
</template>Key Imports
// Reactivity
import { ref, shallowRef, computed, reactive, readonly, toRef, toRefs, toValue } from 'vue'
// Watchers
import { watch, watchEffect, watchPostEffect, onWatcherCleanup } from 'vue'
// Lifecycle
import { onMounted, onUpdated, onUnmounted, onBeforeMount, onBeforeUpdate, onBeforeUnmount } from 'vue'
// Utilities
import { nextTick, defineComponent, defineAsyncComponent } from 'vue'Files
- ATTRIBUTION.mdAdded by AutoGineer886 B
- GENERATION.md133 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md2.4 KiB
- references/advanced-patterns.md6.1 KiB
- references/core-new-apis.md5.6 KiB
- references/script-setup-macros.md4.0 KiB
references/advanced-patterns.md
name: advanced-patterns description: Vue 3 built-in components (Transition, Teleport, Suspense, KeepAlive) and advanced directives
Built-in Components & Directives
Transition
Animate enter/leave of a single element or component.
<template>
<Transition name="fade">
<div v-if="show">Content</div>
</Transition>
</template>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
</style>CSS Classes
| Class | When |
|---|---|
{name}-enter-from | Start state for enter |
{name}-enter-active | Active state for enter (add transitions here) |
{name}-enter-to | End state for enter |
{name}-leave-from | Start state for leave |
{name}-leave-active | Active state for leave |
{name}-leave-to | End state for leave |
Transition Modes
<!-- Wait for leave to complete before enter -->
<Transition name="fade" mode="out-in">
<component :is="currentView" />
</Transition>JavaScript Hooks
<Transition
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
@leave="onLeave"
:css="false"
>
<div v-if="show">Content</div>
</Transition>
<script setup lang="ts">
function onEnter(el: Element, done: () => void) {
// Animate with JS library
gsap.to(el, { opacity: 1, onComplete: done })
}
</script>Appear on Initial Render
<Transition appear name="fade">
<div>Shows with animation on mount</div>
</Transition>TransitionGroup
Animate list items. Each child must have a unique key.
<template>
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item.id">
{{ item.text }}
</li>
</TransitionGroup>
</template>
<style>
.list-enter-active, .list-leave-active {
transition: all 0.3s ease;
}
.list-enter-from, .list-leave-to {
opacity: 0;
transform: translateX(30px);
}
/* Move animation for reordering */
.list-move {
transition: transform 0.3s ease;
}
</style>Teleport
Render content to a different DOM location.
<template>
<button @click="open = true">Open Modal</button>
<Teleport to="body">
<div v-if="open" class="modal">
Modal content rendered at body
</div>
</Teleport>
</template>Props
<!-- CSS selector -->
<Teleport to="#modal-container">
<!-- DOM element -->
<Teleport :to="targetElement">
<!-- Disable teleport conditionally -->
<Teleport to="body" :disabled="isMobile">
<!-- Defer until target exists (Vue 3.5+) -->
<Teleport defer to="#late-rendered-target">Suspense
Handle async dependencies with loading states. Experimental feature.
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>Async Dependencies
Suspense waits for:
Components with
async setup()Components using top-level
awaitin<script setup>Async components created with
defineAsyncComponent
<!-- AsyncComponent.vue -->
<script setup lang="ts">
const data = await fetch('/api/data').then(r => r.json())
</script>Events
<Suspense
@pending="onPending"
@resolve="onResolve"
@fallback="onFallback"
>
...
</Suspense>KeepAlive
Cache component instances when toggled.
<template>
<KeepAlive>
<component :is="currentTab" />
</KeepAlive>
</template>Include/Exclude
<!-- By name (string or regex) -->
<KeepAlive include="ComponentA,ComponentB">
<KeepAlive :include="/^Tab/">
<KeepAlive :include="['TabA', 'TabB']">
<!-- Exclude -->
<KeepAlive exclude="ModalComponent">
<!-- Max cached instances -->
<KeepAlive :max="10">Lifecycle Hooks
import { onActivated, onDeactivated } from 'vue'
onActivated(() => {
// Called when component is inserted from cache
fetchLatestData()
})
onDeactivated(() => {
// Called when component is removed to cache
pauseTimers()
})v-memo
Skip re-renders when dependencies unchanged. Use for performance optimization.
<template>
<div v-for="item in list" :key="item.id" v-memo="[item.selected]">
<!-- Only re-renders when item.selected changes -->
<ExpensiveComponent :item="item" />
</div>
</template>Equivalent to v-once when empty:
<div v-memo="[]">Never updates</div>v-once
Render once, skip all future updates.
<span v-once>Static: {{ neverChanges }}</span>Custom Directives
Create reusable DOM manipulations.
// Directive definition
const vFocus: Directive<HTMLElement> = {
mounted: (el) => el.focus()
}
// Full hooks
const vColor: Directive<HTMLElement, string> = {
created(el, binding, vnode, prevVnode) {},
beforeMount(el, binding) {},
mounted(el, binding) {
el.style.color = binding.value
},
beforeUpdate(el, binding) {},
updated(el, binding) {
el.style.color = binding.value
},
beforeUnmount(el, binding) {},
unmounted(el, binding) {}
}Directive Arguments & Modifiers
<div v-color:background.bold="'red'">
<script setup lang="ts">
const vColor: Directive<HTMLElement, string> = {
mounted(el, binding) {
// binding.arg = 'background'
// binding.modifiers = { bold: true }
// binding.value = 'red'
el.style[binding.arg || 'color'] = binding.value
if (binding.modifiers.bold) {
el.style.fontWeight = 'bold'
}
}
}
</script>Global Registration
// main.ts
app.directive('focus', {
mounted: (el) => el.focus()
})Type global directives by extending the GlobalDirectives interface (not ComponentCustomProperties):
import type { Directive } from 'vue'
declare module 'vue' {
interface GlobalDirectives {
vFocus: Directive<HTMLElement>
}
}<!-- Source references: - https://vuejs.org/api/built-in-components.html - https://vuejs.org/guide/built-ins/transition.html - https://vuejs.org/guide/built-ins/teleport.html - https://vuejs.org/guide/built-ins/suspense.html - https://vuejs.org/guide/built-ins/keep-alive.html - https://vuejs.org/api/built-in-directives.html - https://vuejs.org/guide/reusability/custom-directives.html -->
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Anthony Fu
- Publisher
- Anthony Fu (Community)
- Source
- antfu/skills · skills/vue · commit f63e9ec
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Anthony Fu or Anthony Fu.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download vue.zip