
Vue Skilld
- 33 installs
- 173 repo stars
- Updated May 5, 2026
- skilld-dev/vue-ecosystem-skills
Helps with ai & agent building tasks.
About
vue-skilld is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- vue-skilld
- AI & Agent Building
- AI-coding skill
Vue Skilld by the numbers
- 33 all-time installs (skills.sh)
- +1 installs in the week ending Jul 20, 2026 (Skillselion tracking)
- Ranked #8,975 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 20, 2026 (Skillselion catalog sync)
npx skills add https://github.com/skilld-dev/vue-ecosystem-skills --skill vue-skilldAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 33 |
|---|---|
| repo stars | ★ 173 |
| Last updated | May 5, 2026 |
| Repository | skilld-dev/vue-ecosystem-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Discussions Index
General Discussions (2)
- #14241: The Naming Conventions OF Vue File (+2) (2025-12-24)
- #14146: Status of
#=v-slot shorthand for default slot (+2) (2025-11-28)
Help/Questions (18)
- #14171: 全局属性怎么在setup中使用 (+1) [answered] (2025-12-05)
- #14039: vue reactivity isn't working when i use it with services. (+1) [answered] (2025-10-30)
- #14220: Correct way of extending tsconfig lib in a vue project (+1) [answered] (2025-12-17)
- #14107: Why does this work? (event-listner prop) (+2) [answered] (2025-11-17)
- #14106: VueJS is impossible to set up (+2) [answered] (2025-11-17)
- #14304: (newbie question) How can I fix uncaught (in promise) DOMException error (+1) [answered] (2026-01-11)
- #14226: Best practise to ensure reactivity of prop values (+1) [answered] (2025-12-19)
- #14189: Specific Build/Run Errors in Vue Web Game Project (+1) [answered] (2025-12-10)
- #14154: 组件二封时原组件事件应该如何定义可以兼顾类型和便捷性? (+1) [answered] (2025-12-01)
- #14365: attributes that are not defined as props are not converted from camelCase to kebap-case (+3) (2026-01-27)
- #14330: TransitionGroup not firing v-move at array.push (+1) [answered] (2026-01-18)
- #14163: Source maps do not work with defineCustomElement and customElement: true (+1) (2025-12-03)
- #14145: Understanding the difference between computed vs in-template expressions (+2) (2025-11-27)
- #14434: How to use isolatedDeclarations with defineComponent in typescript (+1) (2026-02-09)
- #14350: defineModel default value is NOT reactive, buts that's odd (+2) (2026-01-22)
- #14329: About props (+1) (2026-01-17)
- #14254: How to correctly type the native popover API when
strictTemplatesis enabled? (+1) (2025-12-26) - #14156: How can I speed up TypeScript checking in Vue projects? (+2) (2025-12-01)
vue reactivity isn't working when i use it with services.
I wanted to use Angular style services.
My service decorators implementation.
type Constructor<T = any> = new (...args: any[]) => T;
const serviceRegistry = new Map<Constructor, InstanceType<Constructor> | null>();
export function Provide<T extends Constructor>(target: T) {
serviceRegistry.set(target, null);
return target;
}
export function Inject<T extends Constructor>(ServiceClass: T): InstanceType<T> {
let instance = serviceRegistry.get(ServiceClass);
if (!instance) {
instance = new ServiceClass();
serviceRegistry.set(ServiceClass, instance);
}
return instance as InstanceType<T>;
}And when I'm using a ref inside these services
import { Provide } from '@/utils/DI';
import { ref } from 'vue';
@Provide
export class DrawerService {
isDrawerOpen = ref(false);
toggleDrawer() {
this.isDrawerOpen.value = !this.isDrawerOpen.value;
}
}
---
Accepted Answer
@LinusBorg [maintainer]:
In your specific instance, I think your problem is not one of reactivity, but plain Javascript -the problem is not the ref, but the callback (3rd argument in this code:)
useClickOutside([drawerRef, triggerRef], drawerService.toggleDrawer, drawerService.isDrawerOpen);toggleDrawer is a method on the drawerServerice object. If you decouple the method from the object (by passing just the method to the function as the 3rd argument), then the function looses the this context.
I would assume it will work when you do:
useClickOutside([drawerRef, triggerRef], () => drawerService.toggleDrawer(), drawerService.isDrawerOpen);or make the toggleDrawer function not loose its this scope:
old-school-way:
@Provide
export class DrawerService {
isDrawerOpen = ref(false);
constructor() {
this.toggleDrawer = this.toggleDrawer.bind(this)
},
toggleDrawer() {
this.isDrawerOpen.value = !this.isDrawerOpen.value;
}
}VueJS is impossible to set up
Hey guys,
i have been working a lot with Next.js but occasionally have projects that need to be in Vue.
Everytime i use Vue.js, i skip using Eslint and Prettier or accept that most files are marked as "red" because of error messages that are in fact no errors in Vue.
I would want to ask, if there is any guideline or tutorial on how to properly set up Vue.js with the regular tech-stack (Typescript, Eslint, Prettier) or if it is just not supported.
I have been trying to set it up every now and again for a long time now and was never successful.
So far i have tried the following:
- Using the CLI and enable typscript, eslint, prettier out of the box
- Using Vite to try and setup Vue custom without the CLI
Either way, i end up with:
- Prettier not working or formatting Vue ...
---
Accepted Answer
i had same frustration before. the problem is extension conflicts.
fix:
1. disable Vetur completely - its for vue 2 and conflicts with vue 3 2. only keep "Vue - Official" extension (this is the new one, replaces volar) 3. remove "Vue language features (Volar)" - its merged into Vue Official now
so you should only have ONE extension: Vue - Official
for eslint/prettier:
use the new @vue/eslint-config-prettier:
npm create vue@latest my-app
# select yes for typescript, eslint, prettierthis sets up everything correctly. the cli now uses flat eslint config.
your eslint.config.js should look like:
import pluginVue from "eslint-plugin-vue"
import vueTsEslintConfig from "@vue/eslint-config-typescript"
import skipFormatting from "@vue/eslint-config-prettier/skip-formatting"
export default [
...pluginVue.configs["flat/recommended"],
...vueTsEslintConfig(),
skipFormatting,
]...
Why does this work? (event-listner prop)
Hi I am confused over here,
I made a modal component that I can feed with function props. These can even be validated using runtime validation (as stated here). It feels like an anti-pattern as soon as you use a prop name called "onXxx" in this example, I used onCallback. In this example I made the prop a promise so I can showcase the ability to run async calls like this. You can even use the prop to add a conditional in the template-tag or in the script-tag
CallbackComponent.vue ...
---
Accepted Answer
The template attributes all get mapped down into VNode props (not to be confused with component props). The VNode props are the properties passed into the h() calls in a render function.
For v-on (or equivalently @), it'll be mapped onto a VNode prop prefixed with on. e.g. @click becomes the VNode prop onClick. That part is documented at:
- <https://vuejs.org/guide/extras/render-function.html#v-on>
There are a few other places in the docs that allude to this, but that's probably the most explicit. You can also see this using the Vue Playground to inspect the compiled output for a template with a listener.
Inside the child component, any VNode prop can be turned into a component prop by listing it in props (or equivalent with defineProps). While it is more common for events to use emits (or equivalently defineEmits), it is also possible to use props for events. One use case for this is detecting whether an event listener is passed, which isn't possible ...
Understanding the difference between computed vs in-template expressions
I've read the documentation for computed props.
However, I can't really understand if there is any difference between the in-template expressions and the computed props. (From the computed docs I understand that is basically no differences).
I am aware of the fact that the computed props are much more terse and even recommended in the style guide in order for the template to not get cluttered.
What I am trying to understand and determine is if there could be any performance penalty of using in-template expression vs a computed prop.
<div :style="styleObject"></div>
where styleObject is
computed: {
styleObject() {
return {
color: this.color
}
}
}vs
<div :style="{ color }"></div>---
Top Comments
@tt-a1i (+1):
@PengYuanhao:
Computed properties are cached and will only trigger re-caching when dependent properties change, reducing computational work during each render 2. Strong readability and easy maintainability Usage scenarios: Simple concatenation and mathematical operations can use template syntax interpolation directly; for complex logic and extensive reuse, computed properties should be employed
Status of #= v-slot shorthand for default slot
Recently I learned that Vue supports even shorter syntax of v-slot directive for default slot: simply # instead of #default (playground):
<template>
<Comp #="{foo}">{{ foo }}</Comp>
<Comp>
<template #="{foo}">{{ foo }}</template>
</Comp>
</template>However, I have not found any official information about this feature, so I wo...
---
Top Comments
@andreww2012:
Wow, it looks like := and @= shorthands for v-bind=" and v-on=" respectively are also supported. It would be awesome to see them documented too
组件二封时原组件事件应该如何定义可以兼顾类型和便捷性?
<script setup lang="ts">
import type { InputPropsPublic, InputEmits } from 'element-plus'
defineProps<{} & InputPropsPublic>()
// 使用 defineEmits 后,事件会跟 props 一样被组件自身消费掉,无法在 $attrs 里面获取,
// 这里除了 emits 一个一个重新抛出外还有别的比较便捷吗?
const emits = defineEmits<InputEmits>()
</script>
<template>
<ElInput v-bind="{ ...$props, ...$attrs }" />
</template>---
Accepted Answer
覆蓋原本事件:
<script lang="ts" setup>
import type { ComponentProps } from 'vue-component-type-helpers';
import { XTextField } from '@x/ui';
type TextFieldProps = ComponentProps<typeof XTextField>;
interface Props extends /* @vue-ignore */ Omit<TextFieldProps, 'onClick'> { // Exclude a specific event from a component.
// my props
}
defineOptions({
inheritAttrs: false,
});
const props = defineProps<Props>();
const emit = defineEmits<(evt: 'click', payload: MouseEvent) => void>(); // Emit an event with the same name as the original event, but change the operation to your own.
function onMyClick() {
// You can now modify the original event; it will still use the same name as the original.
emit('click', /* ... */);
}
</script>
<template>
<XTextField v-bind="$attrs" @click="onMyClick()" />
</template>How can I speed up TypeScript checking in Vue projects?
Guys, could you give me some advice?
How can I speed up TypeScript checking in Vue projects?
tsc can run selectively for a file: npx tsc --noEmit --skipLibCheck FILE_PATH
but vue-tsc doesn’t seem to allow this.
They promise to speed up the checks with Go in the future, but as far as I know it’s still in beta.
---
Top Comments
@panstromek:
It helps to keep as much code as you can out of Vue files, big Vue files seems to be pretty costly for vue-tsc to process. It also helps to use explicit type annotations on Vue-related things, especially if they require complicated type inference to resolve (e.g. if it involves UnwrapRef or component types). This helps if the type annotation is simpler than the type that is assigned to it and it's used in more places.
@Shyam-Chen:
Ref: https://devblogs.microsoft.com/typescript/progress-on-typescript-7-december-2025/
Source maps do not work with defineCustomElement and customElement: true
Hey all,
I am trying to get source maps to work in a project that is using defineCustomElement and customElement: true, so all component styling is added to the shadowRoot of the custom element. I made a small reproduction repository which you can find here https://github.com/Sanderovich/vue-3.5.25-custom-elements-sourcemap.
With build.sourcemap set to true or inline the source maps are not added to the inline styling in the shadowRoot. Does anybody have an idea how to fix this, or an explanation why this does not work, or did I stumble upon a bug?
---
Top Comments
@edison1105 [maintainer]:
It should not be supported. Currently, only the styles are added to the shadowRoot, and source maps are not included
全局属性怎么在setup中使用
app.config.globalProperties.msg = 'hello' export default { mounted() { console.log(this.msg) // 'hello' } } 怎么在中使用这个全局变量,感觉组件式没有特别好在script 中获取全局变量的便捷模式,这个全局变量在template的说能够使用的,只能用window.msg在main.js进行注册使用吗?
---
Accepted Answer
@baiwusanyu-c [maintainer]:
<script setup>
import { ref, getCurrentInstance } from 'vue'
const instance = getCurrentInstance()
console.log(instance.appContext.config.globalProperties)
const msg = ref('Hello World!')
</script>
<template>
<h1>{{ msg }}</h1>
<input v-model="msg" />
</template>Specific Build/Run Errors in Vue Web Game Project
Hi, I’m getting the following errors when trying to run my Vue game project.
Commands:
npm install
npm run devError Output:
[vite] Internal server error: Failed to resolve import "@/components/GameBoard.vue"
Error: Cannot find module '/src/components/GameBoard.vue'
at resolve (node:internal/modules/esm/resolve:1233)And during build:
Error: Cannot read properties of undefined (reading 'hooks')
at createPluginContainer (vite/dist/node/chunks/dep-56f75469.js:5321)Does anyone know how to fix these module resolution issues?
Thanks!
---
Accepted Answer
The error indicates that Vite can't resolve the file at @/components/GameBoard.vue. Please verify that: The file actually exists in src/components/. The filename matches exactly, including capitalization. Your vite.config.js includes the correct alias: resolve: { alias: { '@': '/src' } } Fixing the path or alias should resolve both errors.
Correct way of extending tsconfig lib in a vue project
My question is kind of related to this topic: https://github.com/orgs/vuejs/discussions/13583 On a fresh vue installation with typescript, a tsconfig.app.json will be created, that extends https://github.com/vuejs/tsconfig/blob/main/tsconfig.dom.json. The tsconfig.dom.json says:
// Target ES2020 to align with Vite.
// <https://vite.dev/config/build-options.html#build-target>
// Support for newer versions of language built-ins are
// left for the users to include, because that would require:
// - either the project doesn't need to support older versions of browsers;
// - or the project has properly included the necessary polyfills.So Baseline availabe features like Object.groupBy are unknown to typescript. As far as I understand, I would...
---
Accepted Answer
Yeah unfortunately thats how TypeScript works - the lib array doesnt merge, it completely overrides.
Your approach is correct but theres a cleaner way. Instead of manually listing all libs, you can check what the base config includes and just add what you need:
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"lib": ["ES2020", "DOM", "DOM.Iterable", "ESNext.Object"]
}
}For Object.groupBy specifically, you need ESNext or ES2024 in your lib:
{
"compilerOptions": {
"lib": ["ES2020", "DOM", "DOM.Iterable", "ESNext"]
}
}Or if you only want Object.groupBy without all ESNext stuff:
{
"compilerOptions": {
"lib": ["ES2020", "DOM", "DOM.Iterable", "ES2024"]
}
}The thing is - when base tsconfig updates, you would need to update yours too. Theres no automatic merge unfortunately.
One workaround some people use is to not extend for compilerOptions and just copy ...
Best practise to ensure reactivity of prop values
We have a fairly large SaaS product, and it relies on a lot of props being used in components.
With the arrival of being able to destructure props I thought something like this would work:
const { thingId } = defineProps<{
thingId: string
}>()
const enabled = computed (() => !!thingId)
const { data: thing, isLoading: isLoadingThing } = getThingQuery(thingId, { enabled })However, it turns out that the query example won't rerun when thingId changes.
The way we've done this to date is:
const props = defineProps<{
thingId: string
}>()
const thingId = computed(() => props.thingId)
const enabled = computed(() => !!thingId.value)
const { data: thing, isLoading: isLoadingThing } = getThingQuery(thingId, { enabled })I've since com...
---
Accepted Answer
When using prop destructuring for thingId, the compiler will rewrite uses of thingId to props.thingId. If something wouldn't work with props.thingId then it won't work with props destructuring either.
For example, with code like this:
getThingQuery(thingId)The compiler will rewrite it to something like this:
getThingQuery(props.thingId)Importantly, that is passing the current value of props.thingId to getThingQuery. If that value changes later, getThingQuery won't know anything about it.
As you noted, you can use computed to get around this problem when using props explicitly:
const t = computed(() => props.thingId)
getThingQuery(t)That's fine, but computed comes with some extra internal overhead that isn't really needed for reading a single property. Using toRef is slightly more lightweight:
// toRef with a function, similar to `computed`
const t = toRef(() => props.thingId)
getThingQuery(t)The Naming Conventions OF Vue File
In a Vue 3 scaffolding project, I noticed that the file naming convention uses Pascal Case (e.g., HelloWorld.vue). Within the file, you can specify a name attribute to define the component name. This allows the name attribute to be different from the file name. The only reason we found for this was that third-party component checks require component names to have more than one word, which could be achieved by changing the name field. However, this makes code maintenance confusing, as the component name may not correspond to the file name. We prefer to change the file name to meet the requirements.
In other files, we use components in the same way as the file name, e.g., <HelloWorld></HelloWorld>. I thought that by adhering to this convention, my project would look consistent. However, w...
---
Top Comments
@ismaildasci:
Hey, totally get the frustration here - the naming convention situation can feel messy at first, but there is actually a consistent approach that works well.
The Vue Style Guide recommendation:
PascalCase for both file names AND template usage is the preferred convention. So HelloWorld.vue as the file name and <HelloWorld /> in your templates. This is what the Vue Style Guide recommends as "strongly recommended".
Why this works best:
...
How to correctly type the native popover API when strictTemplates is enabled?
The Popover API is already included in the 2024 browser baseline, so why doesn't Vue include definitions for these APIs? <img width="1251" height="579" alt="image" src="https://github.com/user-attachments/assets/1325ea9a-cb1c-4a28-baad-29fd5751c944" />
I don't like this:
declare module "vue" {
export interface HTMLAttributes {
popover?: "auto" | "manual" | "" | boolean;
popovertarget?: string;
popovertargetaction?: "toggle" | "show" | "hide";
}
}---
Top Comments
@rzzf (+1):
I’ve submitted a pull request. Let’s wait for the official review.
(newbie question) How can I fix uncaught (in promise) DOMException error
Vue version: 3.5.25 vue-router version: 4.6.3
I'm doing my very first pet-project at all. The error only occurs in Firefox. Everything works fine in Chromium, with no errors, as shown in the second screenshot. I just don't know where to look.
<img width="1377" height="965" alt="image" src="https://github.com/user-attachments/assets/57654464-0aa3-4202-a7b9-2d43e6a39f79" /> <img width="502" height="226" alt="image" src="https://github.com/user-attachments/assets/c431e188-ce3c-4af2-854b-5354fd55517f" />
---
Accepted Answer
I solved the problem. That warning didn't mean anything. I have a fairly large project with a lot of code (for a beginner's pet project). For some reason, Chromium-like browsers allowed me to accidentally write a semicolon in the component properties, which I didn't notice, while Firefox complained about it but didn't explain anything. Commenting out the components one by one helped. Look below and find it
<div class="flex flex-row justify-center gap-4 py-2">
<AtomRegularButton
:icon="FolderPlusIcon"
:customIconSize="5"
:without-paddings-for-icon="true"
@click="workspacesStore.addWorkspace('New space')"
;
/>
<AtomRegularButton
:icon="PencilSquareIcon"
:custom-icon-size="5"
@click="
() => {
toggleTaskActions();
showInputForChangeWorkspaceTitle = false;
}
"
:without-paddings-for-icon="true"
/>
</div>About props
When I was learning how to use a ref object as a prop,I couldn't understand why
const { foo } = defineProps(["foo"])
watch(foo,()=>{}) // Not work
watchEffect(()=>{
foo
...
}) //Work wellI know it will compile to
const prop = defineProps(["foo"])
watch(prop.foo,()=>{}) // Not work
watchEffect(()=>{
prop.foo
...
}) //Work wellBut I can't understand why prop.foo can't detected by watch() AI told me it will auto unpack ref data,so prop.foo is just normal object But I have learnt watchEffect() detect releative data by call it's getter or setter,if prop.foo is just normal object,it doesn't have getter or setter,so what causes this
Because it's difficult to read all source code about this part for me,so I came to there for help Thanks
---
Top Comments
@skirtles-code (+1):
Props destructuring is a distraction here. You're essentially correct, that it compiles watch(foo, ... to watch(props.foo, ..., so the real question is why doesn't watch(props.foo, ... do what you want?
To be a bit more explicit, consider this code:
const props = defineProps(['foo'])
watch(props.foo, () => {
console.log('changed')
})As you noted, this won't work. Here's a Playground showing that:
- [Playground](https://play.vuejs.org/#eNqFUstu2zAQ/JUFL1IQQ0LRngzZaBvk0AJtgz5OZQ8qtZKZUCRBUo4LQf/eJRU5ThA4N+3O7HBWOyP7YG2xH5CtWeWFkzaAxzDYLdeyt8YFGMFhCxO0zvSQETU...
@ismaildasci:
Hey, I had the same confusion before so let me explain what I learned.
When you destructure props like this:
const { foo } = defineProps(["foo"])you basically extract the value at that moment. Its not reactive anymore, just a plain value. Thats why watch() cant detect changes.
But watchEffect works different - it tracks whatever you access inside it while running. So when you use foo inside watchEffect, Vue still catches it.
What you can do:
Use getter function in watch:
const { foo } = defineProps(["foo"])
watch(() => foo, (newVal) => {
console.log(newVal)
})TransitionGroup not firing v-move at array.push
Hello everyone. Sorry for my bad English, I'm using a translator.
I'm trying to create a toasts component for Vue 3. The key is that I need new elements to be at the bottom, and older elements to fade upward when a new element is added. The entire component is positioned at the bottom left.
The problem is that v-move only starts working when the list overflows and older toasts are deleted.
As I understand it, when adding an element, I call list.push(), which doesn't change the position of the other elements but simply adds the new element to the end, so v-move doesn't work.
I'm already racking my brain trying to implement this. I've tried display flex and scaleY. Nothing works. Please help.
Link to the playground: https://play.vuejs.org/#eNqFVMlu2zAQ/ZWBcrCC2LLTtBfVMdAWQZECX...
---
Accepted Answer
If I set the Vue version to 3.5.22 in the Playground it seems to work correctly. This seems to be a regression in 3.5.23.
defineModel default value is NOT reactive, buts that's odd
So I have a component, where I need to use the v-model in a scenario and one I don't.
const state = defineModel<CustomerLookupState>('lookup', {
default: () =>({
phone_number: '',
birthday: null,
location_id: null,
}),
});And then in my component, I bind the state to some form component.
In scenario 1, where I bind the v-model to my component, everything is working fine.
In scenario 2, I don't need to bind the v-model, I want to use the defineModel and need the default value.
As per https://github.com/vuejs/core/issues/10009, it states I should wrap it in reactive. That works.
This feels weird, because of the use-case that you can use defineModel as a "standalone" ref, but if I define a default value, the defi...
---
Top Comments
@sunnypatell:
@yooouuri this is by design. defineModel compiles to useModel() in packages/runtime-core/src/helpers/useModel.ts, which uses customRef internally. the default value gets stored in a plain localValue variable, not a reactive proxy.
when you do state.value.phone_number = 'x', you're mutating a property on a plain object. the customRef's set() is never called (you're not replacing state.value, just mutating a nested property), so no reactivity triggers.
...
attributes that are not defined as props are not converted from camelCase to kebap-case
I came across this today and wonder if this is really intended. Every attribute name that is not defined as prop is just converted to lowercase when applied to the component. So things like ariaControls become ariacontrols instead of aria-controls
However this does not happen, if the attrubute falls through and hits another component that does define it as prop. I guess this happens because setAttribute ultimately just lowercases the attribute when it hits an html element but otherwise just passes it though as i.
So here are some examples:
<button dataTestid="foo" />However, when we define it as prop it obviosuly is passed correctly because vue converts forth and back:
defineProps<{dataTestid: string}>()---
Top Comments
@sunnypatell:
@Fuzzyma this is a real bug in how <slot> attributes interact with v-bind on HTML elements.
the root cause is in `packages/compiler-core/src/transforms/transformSlotOutlet.ts`. when processing <slot> attributes, Vue's compiler explicitly camelizes every attribute name:
p.name = camelize(p.name)so data-testid becomes dataTestid and aria-controls becomes ariaControls in the scope object.
...
How to use isolatedDeclarations with defineComponent in typescript
When I am trying to speed up with oxc, I need to enable isolatedDeclarations for dts generation.
<img width="2064" height="648" alt="image" src="https://github.com/user-attachments/assets/1eb2a65e-0fad-4a10-8ec0-27bb37d1fbc5" />
However, I do not see any possibility to write a detailed type by hand. Is there anyway to "declare these components" gracefully?
---
Top Comments
@gitboyzcf (+2):
下面是在启用 `isolatedDeclarations` 的前提下,优雅生成 d.ts 的常用做法与注意点(以 Vue + TS 为例),尽量不手写冗长类型:
---
核心思路
isolatedDeclarations 要求每个文件都能独立产出声明,因此禁止依赖“类型推断链过长/跨文件推断/复杂条件类型展开”。解决方案是:
1. 显式导出类型 2. 把推断结果“固定住” 3. 避免运行时值推断出复杂类型
---
推荐做法 1:显式导出 Props/Emits 类型
export interface FadeInExpandTransitionProps {
group?: boolean
appear?: boolean
width?: boolean
mode?: 'default' | 'in-out' | 'out-in'
onLeave?: () => void
onAfterLeave?: () => void
onAfterEnter?: () => void
}然后:
export default defineComponent({
props: {
// ...使用 PropType 显式标注
} as PropType<FadeInExpandTransitionProps>,
})Docs Index
- Vue.js - The Progressive JavaScript Framework
about (6)
- Code Of Conduct: In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project an...
- Community Guide: Vue's community is growing incredibly fast and if you're reading this, there's a good chance you're ready to join it. So... welcome!
- Frequently Asked Questions: Vue is an independent, community-driven project. It was created by Evan You in 2014 as a personal side project. Today, Vue is actively maintained b...
- Vue.js Privacy Policy: This Privacy Policy describes the Vue.js organization ("Vue", "we", "us" or "our") practices for handling your information in connection with this ...
- Releases: A full changelog of past releases is available on GitHub.
- Meet the Team
api (29)
- Application API: Creates an application instance.
- Built-in Components: :::info Registration and Usage
Built-in components can be used directly in templates without needing to be registered. They are also tree-shakeable...
- Built-in Directives: Update the element's text content.
- Built-in Special Attributes: The key special attribute is primarily used as a hint for Vue's virtual DOM algorithm to identify vnodes when diffing the new list of nodes against...
- Built-in Special Elements: :::info Not Components
<component>, <slot> and <template> are component-like features and part of the template syntax. They are not true components...
- Compile-Time Flags: :::tip
Compile-time flags only apply when using the esm-bundler build of Vue (i.e. vue/dist/vue.esm-bundler.js). :::
- Component Instance: :::info
This page documents the built-in properties and methods exposed on the component public instance, i.e. this.
- Composition API: <br>Dependency Injection: Provides a value that can be injected by descendant components.
- Composition API: Helpers: Returns the attrs object from the Setup Context, which includes the fallthrough attributes of the current component. This is intended to be used in...
- Composition API: Lifecycle Hooks: :::info Usage Note
All APIs listed on this page must be called synchronously during the setup() phase of a component. See Guide - Lifecycle Hooks f...
- Composition API: setup(): The setup() hook serves as the entry point for Composition API usage in components in the following cases:
- Custom Elements API: This method accepts the same argument as defineComponent, but instead returns a native Custom Element class constructor.
- Custom Renderer API: Creates a custom renderer. By providing platform-specific node creation and manipulation APIs, you can leverage Vue's core runtime to target non-DO...
- Global API: General: Exposes the current version of Vue.
- API Reference
- Options: Composition: Provide values that can be injected by descendant components.
- Options: Lifecycle: :::info See also
For shared usage of lifecycle hooks, see Guide - Lifecycle Hooks :::
- Options: Misc: Explicitly declare a display name for the component.
- Options: Rendering: A string template for the component.
- Options: State: A function that returns the initial reactive state for the component instance.
- Reactivity API: Advanced: Shallow version of ref().
- Reactivity API: Core: :::info See also
To better understand the Reactivity APIs, it is recommended to read the following chapters in the guide:
- Reactivity API: Utilities: Checks if a value is a ref object.
- Render Function APIs: Creates virtual DOM nodes (vnodes).
- SFC CSS Features: When a tag has the scoped attribute, its CSS will apply to elements of the current component only. This is similar to the style encapsulati...
- [](./api/sfc-script-setup.md): is a compile-time syntactic sugar for using Composition API inside Single-File Components (SFCs). It is the recommended syntax if yo...
- SFC Syntax Specification: A Vue Single-File Component (SFC), conventionally using the .vue file extension, is a custom file format that uses an HTML-like syntax to describe ...
- Server-Side Rendering API: Renders input as a Node.js Readable stream.
- Utility Types: :::info
This page only lists a few commonly used utility types that may need explanation for their usage. For a full list of exported types, consul...
ecosystem (2)
- Community Newsletters: There are many great newsletters / Vue-dedicated blogs from the community bringing you latest news and happenings in the Vue ecosystem. Here is a n...
- themes
error-reference (1)
- Production Error Code Reference: In production builds, the 3rd argument passed to the following error handler APIs will be a short code instead of the full information string:
examples (1)
- Examples
glossary (1)
- Glossary: This glossary is intended to provide some guidance about the meanings of technical terms that are in common usage when talking about Vue. It is int...
guide/best-practices (4)
- Accessibility: Web accessibility (also known as a11y) refers to the practice of creating websites that can be used by anyone — be that a person with a disability,...
- Performance: Vue is designed to be performant for most common use cases without much need for manual optimizations. However, there are always challenging scenar...
- Production Deployment: During development, Vue provides a number of features to improve the development experience:
- Security: When a vulnerability is reported, it immediately becomes our top concern, with a full-time contributor dropping everything to work on it. To report...
guide/built-ins (5)
- KeepAlive: <KeepAlive> is a built-in component that allows us to conditionally cache component instances when dynamically switching between multiple components.
- Suspense: :::warning Experimental Feature
<Suspense> is an experimental feature. It is not guaranteed to reach stable status and the API may change before it...
- Teleport: <Teleport> is a built-in component that allows us to "teleport" a part of a component's template into a DOM node that exists outside the DOM hierar...
- TransitionGroup: <TransitionGroup> is a built-in component designed for animating the insertion, removal, and order change of elements or components that are render...
- Transition: Vue offers two built-in components that can help work with transitions and animations in response to changing state:
guide/components (8)
- Async Components: In large applications, we may need to divide the app into smaller chunks and only load a component from the server when it's needed. To make that p...
- Fallthrough Attributes: A "fallthrough attribute" is an attribute or v-on event listener that is passed to a component, but is not explicitly declared in the receiving com...
- Component Events: A component can emit custom events directly in template expressions (e.g. in a v-on handler) using the built-in $emit method:
- Props: Vue components require explicit props declaration so that Vue knows what external props passed to the component should be treated as fallthrough at...
- Provide / Inject: Usually, when we need to pass data from the parent to a child component, we use props. However, imagine the case where we have a large component tr...
- Component Registration: A Vue component needs to be "registered" so that Vue knows where to locate its implementation when it is encountered in a template. There are two w...
- Slots: We have learned that components can accept props, which can be JavaScript values of any type. But how about template content? In some cases, we may...
- Component v-model: v-model can be used on a component to implement a two-way binding.
guide/essentials (13)
- Creating a Vue Application: Every Vue application starts by creating a new application instance with the createApp function:
- Class and Style Bindings: A common need for data binding is manipulating an element's class list and inline styles. Since class and style are both attributes, we can use v-b...
- Components Basics: Components allow us to split the UI into independent and reusable pieces, and think about each piece in isolation. It's common for an app to be org...
- Computed Properties: In-template expressions are very convenient, but they are meant for simple operations. Putting too much logic in your templates can make them bloat...
- Conditional Rendering: The directive v-if is used to conditionally render a block. The block will only be rendered if the directive's expression returns a truthy value.
- Event Handling: We can use the v-on directive, which we typically shorten to the @ symbol, to listen to DOM events and run some JavaScript when they're triggered. ...
- Form Input Bindings: When dealing with forms on the frontend, we often need to sync the state of form input elements with corresponding state in JavaScript. It can be c...
- Lifecycle Hooks: Each Vue component instance goes through a series of initialization steps when it's created - for example, it needs to set up data observation, com...
- List Rendering: We can use the v-for directive to render a list of items based on an array. The v-for directive requires a special syntax in the form of item in it...
- Reactivity Fundamentals: :::tip API Preference
This page and many other chapters later in the guide contain different content for the Options API and the Composition API. Y...
- Template Refs: While Vue's declarative rendering model abstracts away most of the direct DOM operations for you, there may still be cases where we need direct acc...
- Template Syntax: Vue uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying component instance's data. All Vue ...
- Watchers: Computed properties allow us to declaratively compute derived values. However, there are cases where we need to perform "side effects" in reaction ...
guide/extras (8)
- Animation Techniques: Vue provides the <Transition> and <TransitionGroup> components for handling enter / leave and list transitions. However, there are many other ways ...
- Composition API FAQ: :::tip
This FAQ assumes prior experience with Vue - in particular, experience with Vue 2 while primarily using Options API. :::
- Reactivity in Depth: One of Vue’s most distinctive features is the unobtrusive reactivity system. Component state consists of reactive JavaScript objects. When you modi...
- Reactivity Transform: :::danger Removed Experimental Feature
Reactivity Transform was an experimental feature, and has been removed in the latest 3.4 release. Please rea...
- Render Functions & JSX: Vue recommends using templates to build applications in the vast majority of cases. However, there are situations where we need the full programmat...
- Rendering Mechanism: How does Vue take a template and turn it into actual DOM nodes? How does Vue update those DOM nodes efficiently? We will attempt to shed some light...
- Ways of Using Vue: We believe there is no "one size fits all" story for the web. This is why Vue is designed to be flexible and incrementally adoptable. Depending on ...
- Vue and Web Components: Web Components is an umbrella term for a set of web native APIs that allows developers to create reusable custom elements.
guide (2)
- Introduction: :::info You are reading the documentation for Vue 3!
- Quick Start: :::tip Prerequisites
guide/reusability (3)
- Composables: :::tip
This section assumes basic knowledge of Composition API. If you have been learning Vue with Options API only, you can set the API Preference...
- Custom Directives: In addition to the default set of directives shipped in core (like v-model or v-show), Vue also allows you to register your own custom directives.
- Plugins: Plugins are self-contained code that usually add app-level functionality to Vue. This is how we install a plugin:
guide/scaling-up (6)
- Routing: Routing on the server side means the server is sending a response based on the URL path that the user is visiting. When we click on a link in a tra...
- Single-File Components: Vue Single-File Components (a.k.a. .vue files, abbreviated as SFC) is a special file format that allows us to encapsulate the template, logic, and ...
- Server-Side Rendering (SSR): Vue.js is a framework for building client-side applications. By default, Vue components produce and manipulate DOM in the browser as output. Howeve...
- State Management: Technically, every Vue component instance already "manages" its own reactive state. Take a simple counter component as an example:
- Testing: Automated tests help you and your team build complex Vue applications quickly and confidently by preventing regressions and encouraging you to brea...
- Tooling: You don't need to install anything on your machine to try out Vue SFCs - there are online playgrounds that allow you to do so right in the browser:
guide/typescript (3)
- TypeScript with Composition API: When using , the defineProps() macro supports inferring the props types based on its argument:
- TypeScript with Options API: :::tip
While Vue does support TypeScript usage with Options API, it is recommended to use Vue with TypeScript via Composition API as it offers simp...
- Using Vue with TypeScript: A type system like TypeScript can detect many common errors via static analysis at build time. This reduces the chance of runtime errors in product...
partners (3)
- [[partnerId]](./partners/[partnerId].md)
- all
- Vue Partners
sponsor (1)
- Become a Vue.js Sponsor: Vue.js is an MIT licensed open source project and completely free to use.
The tremendous amount of effort needed to maintain such a large ecosystem...
style-guide (5)
- Style Guide: ::: warning Note
This Vue.js Style Guide is outdated and needs to be reviewed. If you have any questions or suggestions, please open an issue. :::
- Priority A Rules: Essential: ::: warning Note
This Vue.js Style Guide is outdated and needs to be reviewed. If you have any questions or suggestions, please open an issue. :::
- Priority C Rules: Recommended: ::: warning Note
This Vue.js Style Guide is outdated and needs to be reviewed. If you have any questions or suggestions, please open an issue. :::
- Priority B Rules: Strongly Recommended: ::: warning Note
This Vue.js Style Guide is outdated and needs to be reviewed. If you have any questions or suggestions, please open an issue. :::
- Priority D Rules: Use with Caution: ::: warning Note
This Vue.js Style Guide is outdated and needs to be reviewed. If you have any questions or suggestions, please open an issue. :::
translations (1)
- Translations: The Vue documentation has recently undergone a major revision, so translations in other languages are still missing or work-in-progress.
tutorial (1)
- Tutorial
tutorial/src/step-1 (1)
- Getting Started: Welcome to the Vue tutorial!
tutorial/src/step-10 (1)
- Watchers: Sometimes we may need to perform "side effects" reactively - for example, logging a number to the console when it changes. We can achieve this with...
tutorial/src/step-11 (1)
- Components: So far, we've only been working with a single component. Real Vue applications are typically created with nested components.
tutorial/src/step-12 (1)
- Props: A child component can accept input from the parent via props. First, it needs to declare the props it accepts:
tutorial/src/step-13 (1)
- Emits: In addition to receiving props, a child component can also emit events to the parent:
tutorial/src/step-14 (1)
- Slots: In addition to passing data via props, the parent component can also pass down template fragments to the child via slots:
tutorial/src/step-15 (1)
- You Did It!: You have finished the tutorial!
tutorial/src/step-2 (1)
- Declarative Rendering: What you see in the editor is a Vue Single-File Component (SFC). An SFC is a reusable self-contained block of code that encapsulates HTML, CSS and ...
tutorial/src/step-3 (1)
- Attribute Bindings: In Vue, mustaches are only used for text interpolation. To bind an attribute to a dynamic value, we use the v-bind directive:
tutorial/src/step-4 (1)
- Event Listeners: We can listen to DOM events using the v-on directive:
tutorial/src/step-5 (1)
- Form Bindings: Using v-bind and v-on together, we can create two-way bindings on form input elements:
tutorial/src/step-6 (1)
- Conditional Rendering: We can use the v-if directive to conditionally render an element:
tutorial/src/step-7 (1)
- List Rendering: We can use the v-for directive to render a list of elements based on a source array:
tutorial/src/step-8 (1)
- Computed Property: Let's keep building on top of the todo list from the last step. Here, we've already added a toggle functionality to each todo. This is done by addi...
tutorial/src/step-9 (1)
- Lifecycle and Template Refs: So far, Vue has been handling all the DOM updates for us, thanks to reactivity and declarative rendering. However, inevitably there will be cases w...
Code Of Conduct {#code-of-conduct}
Our Pledge {#our-pledge}
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, political party, or sexual identity and orientation. Note, however, that religion, political party, or other ideological affiliation provide no exemptions for the behavior we outline as unacceptable in this Code of Conduct.
Our Standards {#our-standards}
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
Our Responsibilities {#our-responsibilities}
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
Scope {#scope}
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
Enforcement {#enforcement}
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at community@vuejs.org. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
Attribution {#attribution}
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq
[homepage]: https://www.contributor-covenant.org
Community Guide {#community-guide}
Vue's community is growing incredibly fast and if you're reading this, there's a good chance you're ready to join it. So... welcome!
Now we'll answer both what the community can do for you and what you can do for the community.
Resources {#resources}
Code of Conduct {#code-of-conduct}
Our Code of Conduct is a guide to make it easier to enrich all of us and the technical communities in which we participate.
Stay in the Know {#stay-in-the-know}
- Follow our official Twitter account.
- Follow our team members on Twitter or GitHub.
- Follow the RFC discussions.
- Subscribe to the official blog.
Get Support {#get-support}
- Discord Chat: A place for Vue devs to meet and chat in real time.
- Forum: The best place to ask questions and get answers about Vue and its ecosystem.
- DEV Community: Share and discuss Vue related topics on Dev.to.
- Meetups: Want to find local Vue enthusiasts like yourself? Interested in becoming a community leader? We have the help and support you need right here!
- GitHub: If you have a bug to report or feature to request, that's what the GitHub issues are for. Please respect the rules specified in each repository's issue template.
- Twitter Community (unofficial): A Twitter community, where you can meet other Vue enthusiasts, get help, or just chat about Vue.
Explore the Ecosystem {#explore-the-ecosystem}
- The Awesome Vue Page: See what other awesome resources have been published by other awesome people.
- Vue Telescope Explorer: Explore websites made with Vue, with insights on what framework / libraries they use.
- Made with Vue.js: showcases of projects and libraries made with Vue.
- The "Show and Tell" Subforum: Another great place to check out what others have built with and for the growing Vue ecosystem.
What You Can Do {#what-you-can-do}
Help Fellow Users {#help-fellow-users}
Code contribution is not the only form of contribution to the Vue community. Answering a question for a fellow Vue user on Discord or the forum is also considered a valuable contribution.
Help Triage Issues {#help-triage-issues}
Triaging an issue means gathering missing information, running the reproduction, verifying the issue's validity, and investigating the cause of the issue.
We receive many issues in our repositories on GitHub every single day. Our bandwidth is limited compared to the amount of users we have, so issue triaging alone can take an enormous amount of effort from the team. By helping us triage the issues, you are helping us become more efficient, allowing us to spend time on higher priority work.
You don't have to triage an issue with the goal of fixing it (although that would be nice too). Sharing the result of your investigation, for example the commit that led to the bug, can already save us a ton of time.
Contribute Code {#contribute-code}
Contributing bug fixes or new features is the most direct form of contribution you can make.
The Vue core repository provides a contributing guide, which contains pull request guidelines and information regarding build setup and high-level architecture. Other sub-project repositories may also contain its own contribution guide - please make sure to read them before submitting pull requests.
Bug fixes are welcome at any time. For new features, it is best to discuss the use case and implementation details first in the RFC repo.
Share (and Build) Your Experience {#share-and-build-your-experience}
Apart from answering questions and sharing resources in the forum and chat, there are a few other less obvious ways to share and expand what you know:
- Develop learning materials. It's often said that the best way to learn is to teach. If there's something interesting you're doing with Vue, strengthen your expertise by writing a blog post, developing a workshop, or even publishing a gist that you share on social media.
- Watch a repo you care about. This will send you notifications whenever there's activity in that repository, giving you insider knowledge about ongoing discussions and upcoming features. It's a fantastic way to build expertise so that you're eventually able to help address issues and pull requests.
Translate Docs {#translate-docs}
I hope that right now, you're reading this sentence in your preferred language. If not, would you like to help us get there?
See the Translations guide for more details on how you can get involved.
Become a Community Leader {#become-a-community-leader}
There's a lot you can do to help Vue grow in your community:
- Present at your local meetup. Whether it's giving a talk or running a workshop, you can bring a lot of value to your community by helping both new and experienced Vue developers continue to grow.
- Start your own meetup. If there's not already a Vue meetup in your area, you can start your own! Use the resources at events.vuejs.org to help you succeed!
- Help meetup organizers. There can never be too much help when it comes to running an event, so offer a hand to help out local organizers to help make every event a success.
If you have any questions on how you can get more involved with your local Vue community, reach out on Twitter at @vuejs_events!
Frequently Asked Questions {#frequently-asked-questions}
Who maintains Vue? {#who-maintains-vue}
Vue is an independent, community-driven project. It was created by Evan You in 2014 as a personal side project. Today, Vue is actively maintained by a team of both full-time and volunteer members from all around the world, where Evan serves as the project lead. You can learn more about the story of Vue in this documentary.
Vue's development is primarily funded through sponsorships and we have been financially sustainable since 2016. If you or your business benefit from Vue, consider sponsoring us to support Vue's development!
What's the difference between Vue 2 and Vue 3? {#what-s-the-difference-between-vue-2-and-vue-3}
Vue 3 is the current, latest major version of Vue. It contains new features that are not present in Vue 2, such as Teleport, Suspense, and multiple root elements per template. It also contains breaking changes that make it incompatible with Vue 2. Full details are documented in the Vue 3 Migration Guide.
Despite the differences, the majority of Vue APIs are shared between the two major versions, so most of your Vue 2 knowledge will continue to work in Vue 3. Notably, Composition API was originally a Vue-3-only feature, but has now been backported to Vue 2 and is available in Vue 2.7.
In general, Vue 3 provides smaller bundle sizes, better performance, better scalability, and better TypeScript / IDE support. If you are starting a new project today, Vue 3 is the recommended choice. There are only a few reasons for you to consider Vue 2 as of now:
- You need to support IE11. Vue 3 leverages modern JavaScript features and does not support IE11.
If you intend to migrate an existing Vue 2 app to Vue 3, consult the migration guide.
Is Vue 2 Still Supported? {#is-vue-2-still-supported}
Vue 2.7, which was shipped in July 2022, is the final minor release of the Vue 2 version range. Vue 2 has entered maintenance mode: it will no longer ship new features, but will continue to receive critical bug fixes and security updates for 18 months starting from the 2.7 release date. This means Vue 2 reached End of Life on December 31st, 2023.
We believe this should provide plenty of time for most of the ecosystem to migrate over to Vue 3. However, we also understand that there could be teams or projects that cannot upgrade by this timeline while still needing to fulfill security and compliance requirements. We are partnering with industry experts to provide extended support for Vue 2 for teams with such needs - if your team expects to be using Vue 2 beyond the end of 2023, make sure to plan ahead and learn more about Vue 2 Extended LTS.
What license does Vue use? {#what-license-does-vue-use}
Vue is a free and open source project released under the MIT License.
What browsers does Vue support? {#what-browsers-does-vue-support}
The latest version of Vue (3.x) only supports browsers with native ES2016 support. This excludes IE11. Vue 3.x uses ES2016 features that cannot be polyfilled in legacy browsers, so if you need to support legacy browsers, you will need to use Vue 2.x instead.
Is Vue reliable? {#is-vue-reliable}
Vue is a mature and battle-tested framework. It is one of the most widely used JavaScript frameworks in production today, with over 1.5 million users worldwide, and is downloaded close to 10 million times a month on npm.
Vue is used in production by renowned organizations in varying capacities all around the world, including Wikimedia Foundation, NASA, Apple, Google, Microsoft, GitLab, Zoom, Tencent, Weibo, Bilibili, Kuaishou, and many more.
Is Vue fast? {#is-vue-fast}
Vue 3 is one of the most performant mainstream frontend frameworks, and handles most web application use cases with ease, without the need for manual optimizations.
In stress-testing scenarios, Vue outperforms React and Angular by a decent margin in the js-framework-benchmark. It also goes neck-and-neck against some of the fastest production-level non-Virtual-DOM frameworks in the benchmark.
Do note that synthetic benchmarks like the above focus on raw rendering performance with dedicated optimizations and may not be fully representative of real-world performance results. If you care more about page load performance, you are welcome to audit this very website using WebPageTest or PageSpeed Insights. This website is powered by Vue itself, with SSG pre-rendering, full page hydration and SPA client-side navigation. It scores 100 in performance on an emulated Moto G4 with 4x CPU throttling over slow 4G networks.
You can learn more about how Vue automatically optimizes runtime performance in the Rendering Mechanism section, and how to optimize a Vue app in particularly demanding cases in the Performance Optimization Guide.
Is Vue lightweight? {#is-vue-lightweight}
When you use a build tool, many of Vue's APIs are "tree-shakable". For example, if you don't use the built-in <Transition> component, it won't be included in the final production bundle.
A hello world Vue app that only uses the absolutely minimal APIs has a baseline size of only around 16kb, with minification and brotli compression. The actual size of the application will depend on how many optional features you use from the framework. In the unlikely case where an app uses every single feature that Vue provides, the total runtime size is around 27kb.
When using Vue without a build tool, we not only lose tree-shaking, but also have to ship the template compiler to the browser. This bloats up the size to around 41kb. Therefore, if you are using Vue primarily for progressive enhancement without a build step, consider using petite-vue (only 6kb) instead.
Some frameworks, such as Svelte, use a compilation strategy that produces extremely lightweight output in single-component scenarios. However, our research shows that the size difference heavily depends on the number of components in the application. While Vue has a heavier baseline size, it generates less code per component. In real-world scenarios, a Vue app may very well end up being lighter.
Does Vue scale? {#does-vue-scale}
Yes. Despite a common misconception that Vue is only suitable for simple use cases, Vue is perfectly capable of handling large scale applications:
- Single-File Components provide a modularized development model that allows different parts of an application to be developed in isolation.
- Composition API provides first-class TypeScript integration and enables clean patterns for organizing, extracting and reusing complex logic.
- Comprehensive tooling support ensures a smooth development experience as the application grows.
- Lower barrier to entry and excellent documentation translate to lower onboarding and training costs for new developers.
How do I contribute to Vue? {#how-do-i-contribute-to-vue}
We appreciate your interest! Please check out our Community Guide.
Should I use Options API or Composition API? {#should-i-use-options-api-or-composition-api}
If you are new to Vue, we provide a high-level comparison between the two styles here.
If you have previously used Options API and are currently evaluating Composition API, check out this FAQ.
Should I use JavaScript or TypeScript with Vue? {#should-i-use-javascript-or-typescript-with-vue}
While Vue itself is implemented in TypeScript and provides first-class TypeScript support, it does not enforce an opinion on whether you should use TypeScript as a user.
TypeScript support is an important consideration when new features are added to Vue. APIs that are designed with TypeScript in mind are typically easier for IDEs and linters to understand, even if you aren't using TypeScript yourself. Everybody wins. Vue APIs are also designed to work the same way in both JavaScript and TypeScript as much as possible.
Adopting TypeScript involves a trade-off between onboarding complexity and long-term maintainability gains. Whether such a trade-off can be justified can vary depending on your team's background and project scale, but Vue isn't really an influencing factor in making that decision.
How does Vue compare to Web Components? {#how-does-vue-compare-to-web-components}
Vue was created before Web Components were natively available, and some aspects of Vue's design (e.g. slots) were inspired by the Web Components model.
The Web Components specs are relatively low-level, as they are centered around defining custom elements. As a framework, Vue addresses additional higher-level concerns such as efficient DOM rendering, reactive state management, tooling, client-side routing, and server-side rendering.
Vue also fully supports consuming or exporting to native custom elements - check out the Vue and Web Components Guide for more details.
Vue.js Privacy Policy {#vue.js-privacy-policy}
Effective Date: May 3, 2024
This Privacy Policy describes the Vue.js organization ("Vue", "we", "us" or "our") practices for handling your information in connection with this website (https://vuejs.org) and our open source-related websites ("Websites") and any content, related documentation, information and services (e.g. tutorials, tools to support the developer workflow, access to resources, etc.) made available to you on this website (collectively, the "Services"). This Privacy Policy describes the personal information we process to support our Services.
For clarity, this Privacy Policy does not apply to any:
1. Use of open source code, documentation or specifications made available on GitHub (https://github.com/), which are governed by the terms of the applicable open source license;
2. Pull requests, issues and any other interactions or features related to participation in open source projects on GitHub, which are governed by GitHub's terms and conditions; or
3. Usage statistics of our published packages on NPM (https://npmjs.com/), which are governed by NPM's terms and conditions; or
4. Usage statistics of our published browser / IDE extensions collected by the browser / IDE vendors. Such statistics are governed by the vendors' respective terms and conditions.
What Kinds of Information Do We Collect? {#what-kinds-of-information-do-we-collect}
We do not collect or store any type of personal data, whether through our websites or through our published npm packages or browser / IDE extensions.
We may collect anonymized data via 3rd party services integrated in our websites:
- Visitor data to our websites. Our website analytics is powered by Fathom Analytics, which doesn't use cookies and complies with the GDPR, ePrivacy (including PECR), COPPA and CCPA. Using this privacy-friendly website analytics software, your IP address is only briefly processed, and we (running this website) have no way of identifying you. As per the CCPA, your personal information is de-identified. You can read more about this on Fathom Analytics' website.
- Fathom Analytics' Privacy Policy: https://usefathom.com/legal/privacy
- Usage data of the search functionality. Our search functionality is powered by Algolia DocSearch, which does not perform any type of user tracking or fingerprinting, and does not use cookies. Algolia services are GDPR compliant, CCPA compliant, and TRUSTe Certified.
- Algolia's privacy policy: https://www.algolia.com/policies/privacy/
- Algolia's security and privacy compliance: https://www.algolia.com/distributed-secure/security-compliance/
How Do We Use Information? {#how-do-we-use-information}
The sole purpose of collecting the aforementioned data is to understand our website traffic and usage in the most privacy-friendly way possible so that we can continually improve our website and documentation quality. The lawful basis as per the GDPR is "Article 6(1)(f); where our legitimate interests are to improve our website and business continually." As per the explanation, no personal data is stored over time.
Data Retention {#data-retention}
All data collected are stored on aforementioned 3rd party services and are subject to the services' respective data retention policies.
Questions {#questions}
If you have any questions about this Privacy Policy or our practices, please contact us via email at hello@vuejs.org.
Releases {#releases}
<p v-if="version"> The current latest stable version of Vue is <strong>{{ version }}</strong>. </p> <p v-else> Checking latest version... </p>
A full changelog of past releases is available on GitHub.
Release Cycle {#release-cycle}
Vue does not have a fixed release cycle.
- Patch releases are released as needed.
- Minor releases always contain new features, with a typical time frame of 3~6 months in between. Minor releases always go through a beta pre-release phase.
- Major releases will be announced ahead of time, and will go through an early discussion phase and alpha / beta pre-release phases.
Semantic Versioning Edge Cases {#semantic-versioning-edge-cases}
Vue releases follow Semantic Versioning with a few edge cases.
TypeScript Definitions {#typescript-definitions}
We may ship incompatible changes to TypeScript definitions between minor versions. This is because:
1. Sometimes TypeScript itself ships incompatible changes between minor versions, and we may have to adjust types to support newer versions of TypeScript.
2. Occasionally we may need to adopt features that are only available in a newer version of TypeScript, raising the minimum required version of TypeScript.
If you are using TypeScript, you can use a semver range that locks the current minor and manually upgrade when a new minor version of Vue is released.
Compiled Code Compatibility with Older Runtime {#compiled-code-compatibility-with-older-runtime}
A newer minor version of Vue compiler may generate code that isn't compatible with the Vue runtime from an older minor version. For example, code generated by Vue 3.2 compiler may not be fully compatible if consumed by the runtime from Vue 3.1.
This is only a concern for library authors, because in applications, the compiler version and the runtime version is always the same. A version mismatch can only happen if you ship pre-compiled Vue component code as a package, and a consumer uses it in a project using an older version of Vue. As a result, your package may need to explicitly declare a minimum required minor version of Vue.
Pre Releases {#pre-releases}
Minor and major releases typically go through a series of pre-release phases: alpha, beta, and release candidate (RC). The number and type of pre-releases depend on the scope of changes. For example, a minor release with limited updates may only have a beta phase, while a major release will usually include all three phases to allow for thorough testing and community feedback.
You can install the latest pre-releases from npm using npx install-vue@alpha, npx install-vue@beta, or npx install-vue@rc. For testing changes not yet included in tagged pre-releases, every commit to the vuejs/core repository is published as a temporary continuous-release preview, which you can install using npx install-vue@edge.
Pre-releases are meant for integration / stability testing, and for early adopters to provide feedback for unstable features. Do not use pre-releases in production. All pre-releases are considered unstable and may ship breaking changes in between, so always pin to exact versions when using pre-releases.
Deprecations {#deprecations}
We may periodically deprecate features that have new, better replacements in minor releases. Deprecated features will continue to work, and will be removed in the next major release after it entered deprecated status.
RFCs {#rfcs}
New features with substantial API surface and major changes to Vue will go through the Request for Comments (RFC) process. The RFC process is intended to provide a consistent and controlled path for new features to enter the framework, and give the users an opportunity to participate and offer feedback in the design process.
The RFC process is conducted in the vuejs/rfcs repo on GitHub.
Experimental Features {#experimental-features}
Some features are shipped and documented in a stable version of Vue, but marked as experimental. Experimental features are typically features that have an associated RFC discussion with most of the design problems resolved on paper, but still lacking feedback from real-world usage.
The goal of experimental features is to allow users to provide feedback for them by testing them in a production setting, without having to use an unstable version of Vue. Experimental features themselves are considered unstable, and should only be used in a controlled manner, with the expectation that the feature may change between any release types.
<TeamPage />
Application API {#application-api}
createApp() {#createapp}
Creates an application instance.
- Type
function createApp(rootComponent: Component, rootProps?: object): App- Details
The first argument is the root component. The second optional argument is the props to be passed to the root component.
- Example
With inline root component:
import { createApp } from 'vue'
const app = createApp({
/* root component options */
})With imported component:
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)- See also Guide - Creating a Vue Application
createSSRApp() {#createssrapp}
Creates an application instance in SSR Hydration mode. Usage is exactly the same as createApp().
app.mount() {#app-mount}
Mounts the application instance in a container element.
- Type
interface App {
mount(rootContainer: Element | string): ComponentPublicInstance
}- Details
The argument can either be an actual DOM element or a CSS selector (the first matched element will be used). Returns the root component instance.
If the component has a template or a render function defined, it will replace any existing DOM nodes inside the container. Otherwise, if the runtime compiler is available, the innerHTML of the container will be used as the template.
In SSR hydration mode, it will hydrate the existing DOM nodes inside the container. If there are mismatches, the existing DOM nodes will be morphed to match the expected output.
For each app instance, mount() can only be called once.
- Example
import { createApp } from 'vue'
const app = createApp(/* ... */)
app.mount('#app')Can also mount to an actual DOM element:
app.mount(document.body.firstChild)app.unmount() {#app-unmount}
Unmounts a mounted application instance, triggering the unmount lifecycle hooks for all components in the application's component tree.
- Type
interface App {
unmount(): void
}app.onUnmount() <sup class="vt-badge" data-text="3.5+" /> {#app-onunmount}
Registers a callback to be called when the app is unmounted.
- Type
interface App {
onUnmount(callback: () => any): void
}app.component() {#app-component}
Registers a global component if passing both a name string and a component definition, or retrieves an already registered one if only the name is passed.
- Type
interface App {
component(name: string): Component | undefined
component(name: string, component: Component): this
}- Example
import { createApp } from 'vue'
const app = createApp({})
// register an options object
app.component('MyComponent', {
/* ... */
})
// retrieve a registered component
const MyComponent = app.component('MyComponent')- See also Component Registration
app.directive() {#app-directive}
Registers a global custom directive if passing both a name string and a directive definition, or retrieves an already registered one if only the name is passed.
- Type
interface App {
directive(name: string): Directive | undefined
directive(name: string, directive: Directive): this
}- Example
import { createApp } from 'vue'
const app = createApp({
/* ... */
})
// register (object directive)
app.directive('myDirective', {
/* custom directive hooks */
})
// register (function directive shorthand)
app.directive('myDirective', () => {
/* ... */
})
// retrieve a registered directive
const myDirective = app.directive('myDirective')- See also Custom Directives
app.use() {#app-use}
Installs a plugin.
- Type
interface App {
use(plugin: Plugin, ...options: any[]): this
}- Details
Expects the plugin as the first argument, and optional plugin options as the second argument.
The plugin can either be an object with an install() method, or just a function that will be used as the install() method. The options (second argument of app.use()) will be passed along to the plugin's install() method.
When app.use() is called on the same plugin multiple times, the plugin will be installed only once.
- Example
import { createApp } from 'vue'
import MyPlugin from './plugins/MyPlugin'
const app = createApp({
/* ... */
})
app.use(MyPlugin)- See also Plugins
app.mixin() {#app-mixin}
Applies a global mixin (scoped to the application). A global mixin applies its included options to every component instance in the application.
:::warning Not Recommended Mixins are supported in Vue 3 mainly for backwards compatibility, due to their widespread use in ecosystem libraries. Use of mixins, especially global mixins, should be avoided in application code.
For logic reuse, prefer Composables instead. :::
- Type
interface App {
mixin(mixin: ComponentOptions): this
}app.provide() {#app-provide}
Provide a value that can be injected in all descendant components within the application.
- Type
interface App {
provide<T>(key: InjectionKey<T> | symbol | string, value: T): this
}- Details
Expects the injection key as the first argument, and the provided value as the second. Returns the application instance itself.
- Example
import { createApp } from 'vue'
const app = createApp(/* ... */)
app.provide('message', 'hello')Inside a component in the application:
<div class="composition-api">
import { inject } from 'vue'
export default {
setup() {
console.log(inject('message')) // 'hello'
}
}</div> <div class="options-api">
export default {
inject: ['message'],
created() {
console.log(this.message) // 'hello'
}
}</div>
app.runWithContext() {#app-runwithcontext}
- Only supported in 3.3+
Execute a callback with the current app as injection context.
- Type
interface App {
runWithContext<T>(fn: () => T): T
}- Details
Expects a callback function and runs the callback immediately. During the synchronous call of the callback, inject() calls are able to look up injections from the values provided by the current app, even when there is no current active component instance. The return value of the callback will also be returned.
- Example
import { inject } from 'vue'
app.provide('id', 1)
const injected = app.runWithContext(() => {
return inject('id')
})
console.log(injected) // 1app.version {#app-version}
Provides the version of Vue that the application was created with. This is useful inside plugins, where you might need conditional logic based on different Vue versions.
- Type
interface App {
version: string
}- Example
Performing a version check inside a plugin:
export default {
install(app) {
const version = Number(app.version.split('.')[0])
if (version < 3) {
console.warn('This plugin requires Vue 3')
}
}
}- See also Global API - version
app.config {#app-config}
Every application instance exposes a config object that contains the configuration settings for that application. You can modify its properties (documented below) before mounting your application.
import { createApp } from 'vue'
const app = createApp(/* ... */)
console.log(app.config)app.config.errorHandler {#app-config-errorhandler}
Assign a global handler for uncaught errors propagating from within the application.
- Type
interface AppConfig {
errorHandler?: (
err: unknown,
instance: ComponentPublicInstance | null,
// `info` is a Vue-specific error info,
// e.g. which lifecycle hook the error was thrown in
info: string
) => void
}- Details
The error handler receives three arguments: the error, the component instance that triggered the error, and an information string specifying the error source type.
It can capture errors from the following sources:
- Component renders
- Event handlers
- Lifecycle hooks
setup()function- Watchers
- Custom directive hooks
- Transition hooks
:::tip In production, the 3rd argument (info) will be a shortened code instead of the full information string. You can find the code to string mapping in the Production Error Code Reference. :::
- Example
app.config.errorHandler = (err, instance, info) => {
// handle error, e.g. report to a service
}- Default
The default error handler will re-throw errors during development and log errors during production. You can configure this using the throwUnhandledErrorInProduction property.
app.config.warnHandler {#app-config-warnhandler}
Assign a custom handler for runtime warnings from Vue.
- Type
interface AppConfig {
warnHandler?: (
msg: string,
instance: ComponentPublicInstance | null,
trace: string
) => void
}- Details
The warning handler receives the warning message as the first argument, the source component instance as the second argument, and a component trace string as the third.
It can be used to filter out specific warnings to reduce console verbosity. All Vue warnings should be addressed during development, so this is only recommended during debug sessions to focus on specific warnings among many, and should be removed once the debugging is done.
:::tip Warnings only work during development, so this config is ignored in production mode. :::
- Example
app.config.warnHandler = (msg, instance, trace) => {
// `trace` is the component hierarchy trace
}app.config.performance {#app-config-performance}
Set this to true to enable component init, compile, render and patch performance tracing in the browser devtool performance/timeline panel. Only works in development mode and in browsers that support the performance.mark API.
- Type:
boolean
- See also Guide - Performance
app.config.compilerOptions {#app-config-compileroptions}
Configure runtime compiler options. Values set on this object will be passed to the in-browser template compiler and affect every component in the configured app. Note you can also override these options on a per-component basis using the `compilerOptions` option.
::: warning Important This config option is only respected when using the full build (i.e. the standalone vue.js that can compile templates in the browser). If you are using the runtime-only build with a build setup, compiler options must be passed to @vue/compiler-dom via build tool configurations instead.
- For
vue-loader: pass via thecompilerOptionsloader option. Also see how to configure it invue-cli.
- For
vite: pass via@vitejs/plugin-vueoptions.
:::
app.config.compilerOptions.isCustomElement {#app-config-compileroptions-iscustomelement}
Specifies a check method to recognize native custom elements.
- Type:
(tag: string) => boolean
- Details
Should return true if the tag should be treated as a native custom element. For a matched tag, Vue will render it as a native element instead of attempting to resolve it as a Vue component.
Native HTML and SVG tags don't need to be matched in this function - Vue's parser recognizes them automatically.
- Example
// treat all tags starting with 'ion-' as custom elements
app.config.compilerOptions.isCustomElement = (tag) => {
return tag.startsWith('ion-')
}- See also Vue and Web Components
app.config.compilerOptions.whitespace {#app-config-compileroptions-whitespace}
Adjusts template whitespace handling behavior.
- Type:
'condense' | 'preserve'
- Default:
'condense'
- Details
Vue removes / condenses whitespace characters in templates to produce more efficient compiled output. The default strategy is "condense", with the following behavior:
1. Leading / ending whitespace characters inside an element are condensed into a single space. 2. Whitespace characters between elements that contain newlines are removed. 3. Consecutive whitespace characters in text nodes are condensed into a single space.
Setting this option to 'preserve' will disable (2) and (3).
- Example
app.config.compilerOptions.whitespace = 'preserve'app.config.compilerOptions.delimiters {#app-config-compileroptions-delimiters}
Adjusts the delimiters used for text interpolation within the template.
- Type:
[string, string]
- Default:
{{ "['\u007b\u007b', '\u007d\u007d']" }}
- Details
This is typically used to avoid conflicting with server-side frameworks that also use mustache syntax.
- Example
// Delimiters changed to ES6 template string style
app.config.compilerOptions.delimiters = ['${', '}']app.config.compilerOptions.comments {#app-config-compileroptions-comments}
Adjusts treatment of HTML comments in templates.
- Type:
boolean
- Default:
false
- Details
By default, Vue will remove the comments in production. Setting this option to true will force Vue to preserve comments even in production. Comments are always preserved during development. This option is typically used when Vue is used with other libraries that rely on HTML comments.
- Example
app.config.compilerOptions.comments = trueapp.config.globalProperties {#app-config-globalproperties}
An object that can be used to register global properties that can be accessed on any component instance inside the application.
- Type
interface AppConfig {
globalProperties: Record<string, any>
}- Details
This is a replacement of Vue 2's Vue.prototype which is no longer present in Vue 3. As with anything global, this should be used sparingly.
If a global property conflicts with a component’s own property, the component's own property will have higher priority.
- Usage
app.config.globalProperties.msg = 'hello'This makes msg available inside any component template in the application, and also on this of any component instance:
export default {
mounted() {
console.log(this.msg) // 'hello'
}
}- See also Guide - Augmenting Global Properties <sup class="vt-badge ts" />
app.config.optionMergeStrategies {#app-config-optionmergestrategies}
An object for defining merging strategies for custom component options.
- Type
interface AppConfig {
optionMergeStrategies: Record<string, OptionMergeFunction>
}
type OptionMergeFunction = (to: unknown, from: unknown) => any- Details
Some plugins / libraries add support for custom component options (by injecting global mixins). These options may require special merging logic when the same option needs to be "merged" from multiple sources (e.g. mixins or component inheritance).
A merge strategy function can be registered for a custom option by assigning it on the app.config.optionMergeStrategies object using the option's name as the key.
The merge strategy function receives the value of that option defined on the parent and child instances as the first and second arguments, respectively.
- Example
const app = createApp({
// option from self
msg: 'Vue',
// option from a mixin
mixins: [
{
msg: 'Hello '
}
],
mounted() {
// merged options exposed on this.$options
console.log(this.$options.msg)
}
})
// define a custom merge strategy for `msg`
app.config.optionMergeStrategies.msg = (parent, child) => {
return (parent || '') + (child || '')
}
app.mount('#app')
// logs 'Hello Vue'- See also Component Instance - `$options`
app.config.idPrefix <sup class="vt-badge" data-text="3.5+" /> {#app-config-idprefix}
Configure a prefix for all IDs generated via useId() inside this application.
- Type:
string
- Default:
undefined
- Example
app.config.idPrefix = 'myApp' // in a component:
const id1 = useId() // 'myApp:0'
const id2 = useId() // 'myApp:1'app.config.throwUnhandledErrorInProduction <sup class="vt-badge" data-text="3.5+" /> {#app-config-throwunhandlederrorinproduction}
Force unhandled errors to be thrown in production mode.
- Type:
boolean
- Default:
false
- Details
By default, errors thrown inside a Vue application but not explicitly handled have different behavior between development and production modes:
- In development, the error is thrown and can possibly crash the application. This is to make the error more prominent so that it can be noticed and fixed during development.
- In production, the error will only be logged to the console to minimize the impact to end users. However, this may prevent errors that only happen in production from being caught by error monitoring services.
By setting app.config.throwUnhandledErrorInProduction to true, unhandled errors will be thrown even in production mode.
Built-in Components {#built-in-components}
:::info Registration and Usage Built-in components can be used directly in templates without needing to be registered. They are also tree-shakeable: they are only included in the build when they are used.
When using them in render functions, they need to be imported explicitly. For example:
import { h, Transition } from 'vue'
h(Transition, {
/* props */
}):::
<Transition> {#transition}
Provides animated transition effects to a single element or component.
- Props
interface TransitionProps {
/**
* Used to automatically generate transition CSS class names.
* e.g. `name: 'fade'` will auto expand to `.fade-enter`,
* `.fade-enter-active`, etc.
*/
name?: string
/**
* Whether to apply CSS transition classes.
* Default: true
*/
css?: boolean
/**
* Specifies the type of transition events to wait for to
* determine transition end timing.
* Default behavior is auto detecting the type that has
* longer duration.
*/
type?: 'transition' | 'animation'
/**
* Specifies explicit durations of the transition.
* Default behavior is wait for the first `transitionend`
* or `animationend` event on the root transition element.
*/
duration?: number | { enter: number; leave: number }
/**
* Controls the timing sequence of leaving/entering transitions.
* Default behavior is simultaneous.
*/
mode?: 'in-out' | 'out-in' | 'default'
/**
* Whether to apply transition on initial render.
* Default: false
*/
appear?: boolean
/**
* Props for customizing transition classes.
* Use kebab-case in templates, e.g. enter-from-class="xxx"
*/
enterFromClass?: string
enterActiveClass?: string
enterToClass?: string
appearFromClass?: string
appearActiveClass?: string
appearToClass?: string
leaveFromClass?: string
leaveActiveClass?: string
leaveToClass?: string
}- Events
@before-enter@before-leave@enter@leave@appear@after-enter@after-leave@after-appear@enter-cancelled@leave-cancelled(v-showonly)@appear-cancelled
- Example
Simple element:
<Transition>
<div v-if="ok">toggled content</div>
</Transition>Forcing a transition by changing the key attribute:
<Transition>
<div :key="text">{{ text }}</div>
</Transition>Dynamic component, with transition mode + animate on appear:
<Transition name="fade" mode="out-in" appear>
<component :is="view"></component>
</Transition>Listening to transition events:
<Transition @after-enter="onTransitionComplete">
<div v-show="ok">toggled content</div>
</Transition>- See also Guide - Transition
<TransitionGroup> {#transitiongroup}
Provides transition effects for multiple elements or components in a list.
- Props
<TransitionGroup> accepts the same props as <Transition> except mode, plus two additional props:
interface TransitionGroupProps extends Omit<TransitionProps, 'mode'> {
/**
* If not defined, renders as a fragment.
*/
tag?: string
/**
* For customizing the CSS class applied during move transitions.
* Use kebab-case in templates, e.g. move-class="xxx"
*/
moveClass?: string
}- Events
<TransitionGroup> emits the same events as <Transition>.
- Details
By default, <TransitionGroup> doesn't render a wrapper DOM element, but one can be defined via the tag prop.
Note that every child in a <transition-group> must be **uniquely keyed** for the animations to work properly.
<TransitionGroup> supports moving transitions via CSS transform. When a child's position on screen has changed after an update, it will get applied a moving CSS class (auto generated from the name attribute or configured with the move-class prop). If the CSS transform property is "transition-able" when the moving class is applied, the element will be smoothly animated to its destination using the FLIP technique.
- Example
<TransitionGroup tag="ul" name="slide">
<li v-for="item in items" :key="item.id">
{{ item.text }}
</li>
</TransitionGroup>- See also Guide - TransitionGroup
<KeepAlive> {#keepalive}
Caches dynamically toggled components wrapped inside.
- Props
interface KeepAliveProps {
/**
* If specified, only components with names matched by
* `include` will be cached.
*/
include?: MatchPattern
/**
* Any component with a name matched by `exclude` will
* not be cached.
*/
exclude?: MatchPattern
/**
* The maximum number of component instances to cache.
*/
max?: number | string
}
type MatchPattern = string | RegExp | (string | RegExp)[]- Details
When wrapped around a dynamic component, <KeepAlive> caches the inactive component instances without destroying them.
There can only be one active component instance as the direct child of <KeepAlive> at any time.
When a component is toggled inside <KeepAlive>, its activated and deactivated lifecycle hooks will be invoked accordingly, providing an alternative to mounted and unmounted, which are not called. This applies to the direct child of <KeepAlive> as well as to all of its descendants.
- Example
Basic usage:
<KeepAlive>
<component :is="view"></component>
</KeepAlive>When used with v-if / v-else branches, there must be only one component rendered at a time:
<KeepAlive>
<comp-a v-if="a > 1"></comp-a>
<comp-b v-else></comp-b>
</KeepAlive>Used together with <Transition>:
<Transition>
<KeepAlive>
<component :is="view"></component>
</KeepAlive>
</Transition>Using include / exclude:
<!-- comma-delimited string -->
<KeepAlive include="a,b">
<component :is="view"></component>
</KeepAlive>
<!-- regex (use `v-bind`) -->
<KeepAlive :include="/a|b/">
<component :is="view"></component>
</KeepAlive>
<!-- Array (use `v-bind`) -->
<KeepAlive :include="['a', 'b']">
<component :is="view"></component>
</KeepAlive>Usage with max:
<KeepAlive :max="10">
<component :is="view"></component>
</KeepAlive>- See also Guide - KeepAlive
<Teleport> {#teleport}
Renders its slot content to another part of the DOM.
- Props
interface TeleportProps {
/**
* Required. Specify target container.
* Can either be a selector or an actual element.
*/
to: string | HTMLElement
/**
* When `true`, the content will remain in its original
* location instead of moved into the target container.
* Can be changed dynamically.
*/
disabled?: boolean
/**
* When `true`, the Teleport will defer until other
* parts of the application have been mounted before
* resolving its target. (3.5+)
*/
defer?: boolean
}- Example
Specifying target container:
<Teleport to="#some-id" />
<Teleport to=".some-class" />
<Teleport to="[data-teleport]" />Conditionally disabling:
<Teleport to="#popup" :disabled="displayVideoInline">
<video src="./my-movie.mp4">
</Teleport>Defer target resolution <sup class="vt-badge" data-text="3.5+" />:
<Teleport defer to="#late-div">...</Teleport>
<!-- somewhere later in the template -->
<div id="late-div"></div>- See also Guide - Teleport
<Suspense> <sup class="vt-badge experimental" /> {#suspense}
Used for orchestrating nested async dependencies in a component tree.
- Props
interface SuspenseProps {
timeout?: string | number
suspensible?: boolean
}- Events
@resolve@pending@fallback
- Details
<Suspense> accepts two slots: the #default slot and the #fallback slot. It will display the content of the fallback slot while rendering the default slot in memory.
If it encounters async dependencies (Async Components and components with `async setup()`) while rendering the default slot, it will wait until all of them are resolved before displaying the default slot.
By setting the Suspense as suspensible, all the async dependency handling will be handled by the parent Suspense. See implementation details
- See also Guide - Suspense
Built-in Directives {#built-in-directives}
v-text {#v-text}
Update the element's text content.
- Expects:
string
- Details
v-text works by setting the element's textContent property, so it will overwrite any existing content inside the element. If you need to update only part of the textContent, you should use mustache interpolations instead (ie. <span v-pre><span>Keep this but update a {{dynamicPortion}}</span></span>).
- Example
<span v-text="msg"></span>
<!-- same as -->
<span>{{msg}}</span>- See also Template Syntax - Text Interpolation
v-html {#v-html}
Update the element's innerHTML.
- Expects:
string
- Details
Contents of v-html are inserted as plain HTML - Vue template syntax will not be processed. If you find yourself trying to compose templates using v-html, try to rethink the solution by using components instead.
::: warning Security Note Dynamically rendering arbitrary HTML on your website can be very dangerous because it can easily lead to XSS attacks. Only use v-html on trusted content and never on user-provided content. :::
In Single-File Components, scoped styles will not apply to content inside v-html, because that HTML is not processed by Vue's template compiler. If you want to target v-html content with scoped CSS, you can instead use CSS modules or an additional, global <style> element with a manual scoping strategy such as BEM.
- Example
<div v-html="html"></div>- See also Template Syntax - Raw HTML
v-show {#v-show}
Toggle the element's visibility based on the truthy-ness of the expression value.
- Expects:
any
- Details
v-show works by setting the display CSS property via inline styles, and will try to respect the initial display value when the element is visible. It also triggers transitions when its condition changes.
- See also Conditional Rendering - v-show
v-if {#v-if}
Conditionally render an element or a template fragment based on the truthy-ness of the expression value.
- Expects:
any
- Details
When a v-if element is toggled, the element and its contained directives / components are destroyed and re-constructed. If the initial condition is falsy, then the inner content won't be rendered at all.
Can be used on <template> to denote a conditional block containing only text or multiple elements.
This directive triggers transitions when its condition changes.
When used together, v-if has a higher priority than v-for. We don't recommend using these two directives together on one element — see the list rendering guide for details.
- See also Conditional Rendering - v-if
v-else {#v-else}
Denote the "else block" for v-if or a v-if / v-else-if chain.
- Does not expect expression
- Details
- Restriction: previous sibling element must have
v-iforv-else-if.
- Can be used on
<template>to denote a conditional block containing only text or multiple elements.
- Example
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>- See also Conditional Rendering - v-else
v-else-if {#v-else-if}
Denote the "else if block" for v-if. Can be chained.
- Expects:
any
- Details
- Restriction: previous sibling element must have
v-iforv-else-if.
- Can be used on
<template>to denote a conditional block containing only text or multiple elements.
- Example
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>- See also Conditional Rendering - v-else-if
v-for {#v-for}
Render the element or template block multiple times based on the source data.
- Expects:
Array | Object | number | string | Iterable
- Details
The directive's value must use the special syntax alias in expression to provide an alias for the current element being iterated on:
<div v-for="item in items">
{{ item.text }}
</div>Alternatively, you can also specify an alias for the index (or the key if used on an Object):
<div v-for="(item, index) in items"></div>
<div v-for="(value, key) in object"></div>
<div v-for="(value, name, index) in object"></div>The default behavior of v-for will try to patch the elements in-place without moving them. To force it to reorder elements, you should provide an ordering hint with the key special attribute:
<div v-for="item in items" :key="item.id">
{{ item.text }}
</div>v-for can also work on values that implement the Iterable Protocol, including native Map and Set.
- See also
- List Rendering
v-on {#v-on}
Attach an event listener to the element.
- Shorthand:
@
- Expects:
Function | Inline Statement | Object (without argument)
- Argument:
event(optional if using Object syntax)
- Modifiers
.stop- callevent.stopPropagation()..prevent- callevent.preventDefault()..capture- add event listener in capture mode..self- only trigger handler if event was dispatched from this element..{keyAlias}- only trigger handler on certain keys..once- trigger handler at most once..left- only trigger handler for left button mouse events..right- only trigger handler for right button mouse events..middle- only trigger handler for middle button mouse events..passive- attaches a DOM event with{ passive: true }.
- Details
The event type is denoted by the argument. The expression can be a method name, an inline statement, or omitted if there are modifiers present.
When used on a normal element, it listens to native DOM events only. When used on a custom element component, it listens to custom events emitted on that child component.
When listening to native DOM events, the method receives the native event as the only argument. If using inline statement, the statement has access to the special $event property: v-on:click="handle('ok', $event)".
v-on also supports binding to an object of event / listener pairs without an argument. Note when using the object syntax, it does not support any modifiers.
- Example
<!-- method handler -->
<button v-on:click="doThis"></button>
<!-- dynamic event -->
<button v-on:[event]="doThis"></button>
<!-- inline statement -->
<button v-on:click="doThat('hello', $event)"></button>
<!-- shorthand -->
<button @click="doThis"></button>
<!-- shorthand dynamic event -->
<button @[event]="doThis"></button>
<!-- stop propagation -->
<button @click.stop="doThis"></button>
<!-- prevent default -->
<button @click.prevent="doThis"></button>
<!-- prevent default without expression -->
<form @submit.prevent></form>
<!-- chain modifiers -->
<button @click.stop.prevent="doThis"></button>
<!-- key modifier using keyAlias -->
<input @keyup.enter="onEnter" />
<!-- the click event will be triggered at most once -->
<button v-on:click.once="doThis"></button>
<!-- object syntax -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>Listening to custom events on a child component (the handler is called when "my-event" is emitted on the child):
<MyComponent @my-event="handleThis" />
<!-- inline statement -->
<MyComponent @my-event="handleThis(123, $event)" />v-bind {#v-bind}
Dynamically bind one or more attributes, or a component prop to an expression.
- Shorthand:
:or.(when using.propmodifier)- Omitting value (when attribute and bound value has the same name, requires 3.4+)
- Expects:
any (with argument) | Object (without argument)
- Argument:
attrOrProp (optional)
- Modifiers
.camel- transform the kebab-case attribute name into camelCase..prop- force a binding to be set as a DOM property (3.2+)..attr- force a binding to be set as a DOM attribute (3.2+).
- Usage
When used to bind the class or style attribute, v-bind supports additional value types such as Array or Objects. See linked guide section below for more details.
When setting a binding on an element, Vue by default checks whether the element has the key defined as a property using an in operator check. If the property is defined, Vue will set the value as a DOM property instead of an attribute. This should work in most cases, but you can override this behavior by explicitly using .prop or .attr modifiers. This is sometimes necessary, especially when working with custom elements.
When used for component prop binding, the prop must be properly declared in the child component.
When used without an argument, can be used to bind an object containing attribute name-value pairs.
- Example
<!-- bind an attribute -->
<img v-bind:src="imageSrc" />
<!-- dynamic attribute name -->
<button v-bind:[key]="value"></button>
<!-- shorthand -->
<img :src="imageSrc" />
<!-- same-name shorthand (3.4+), expands to :src="src" -->
<img :src />
<!-- shorthand dynamic attribute name -->
<button :[key]="value"></button>
<!-- with inline string concatenation -->
<img :src="'/path/to/images/' + fileName" />
<!-- class binding -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]"></div>
<!-- style binding -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>
<!-- binding an object of attributes -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
<!-- prop binding. "prop" must be declared in the child component. -->
<MyComponent :prop="someThing" />
<!-- pass down parent props in common with a child component -->
<MyComponent v-bind="$props" />
<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>The .prop modifier also has a dedicated shorthand, .:
<div :someProperty.prop="someObject"></div>
<!-- equivalent to -->
<div .someProperty="someObject"></div>The .camel modifier allows camelizing a v-bind attribute name when using in-DOM templates, e.g. the SVG viewBox attribute:
<svg :view-box.camel="viewBox"></svg>.camel is not needed if you are using string templates, or pre-compiling the template with a build step.
v-model {#v-model}
Create a two-way binding on a form input element or a component.
- Expects: varies based on value of form inputs element or output of components
- Limited to:
<input><select><textarea>- components
- Modifiers
- `.lazy` - listen to
changeevents instead ofinput - `.number` - cast valid input string to numbers
- `.trim` - trim input
- See also
v-slot {#v-slot}
Denote named slots or scoped slots that expect to receive props.
- Shorthand:
#
- Expects: JavaScript expression that is valid in a function argument position, including support for destructuring. Optional - only needed if expecting props to be passed to the slot.
- Argument: slot name (optional, defaults to
default)
- Limited to:
<template>- components (for a lone default slot with props)
- Example
<!-- Named slots -->
<BaseLayout>
<template v-slot:header>
Header content
</template>
<template v-slot:default>
Default slot content
</template>
<template v-slot:footer>
Footer content
</template>
</BaseLayout>
<!-- Named slot that receives props -->
<InfiniteScroll>
<template v-slot:item="slotProps">
<div class="item">
{{ slotProps.item.text }}
</div>
</template>
</InfiniteScroll>
<!-- Default slot that receive props, with destructuring -->
<Mouse v-slot="{ x, y }">
Mouse position: {{ x }}, {{ y }}
</Mouse>- See also
- Components - Slots
v-pre {#v-pre}
Skip compilation for this element and all its children.
- Does not expect expression
- Details
Inside the element with v-pre, all Vue template syntax will be preserved and rendered as-is. The most common use case of this is displaying raw mustache tags.
- Example
<span v-pre>{{ this will not be compiled }}</span>v-once {#v-once}
Render the element and component once only, and skip future updates.
- Does not expect expression
- Details
On subsequent re-renders, the element/component and all its children will be treated as static content and skipped. This can be used to optimize update performance.
<!-- single element -->
<span v-once>This will never change: {{msg}}</span>
<!-- the element have children -->
<div v-once>
<h1>Comment</h1>
<p>{{msg}}</p>
</div>
<!-- component -->
<MyComponent v-once :comment="msg"></MyComponent>
<!-- `v-for` directive -->
<ul>
<li v-for="i in list" v-once>{{i}}</li>
</ul>Since 3.2, you can also memoize part of the template with invalidation conditions using `v-memo`.
v-memo {#v-memo}
- Only supported in 3.2+
- Expects:
any[]
- Details
Memoize a sub-tree of the template. Can be used on both elements and components. The directive expects a fixed-length array of dependency values to compare for the memoization. If every value in the array was the same as last render, then updates for the entire sub-tree will be skipped. For example:
<div v-memo="[valueA, valueB]">
...
</div>When the component re-renders, if both valueA and valueB remain the same, all updates for this <div> and its children will be skipped. In fact, even the Virtual DOM VNode creation will also be skipped since the memoized copy of the sub-tree can be reused.
It is important to specify the memoization array correctly, otherwise we may skip updates that should indeed be applied. v-memo with an empty dependency array (v-memo="[]") would be functionally equivalent to v-once.
Usage with `v-for`
v-memo is provided solely for micro optimizations in performance-critical scenarios and should be rarely needed. The most common case where this may prove helpful is when rendering large v-for lists (where length > 1000):
<div v-for="item in list" :key="item.id" v-memo="[item.id === selected]">
<p>ID: {{ item.id }} - selected: {{ item.id === selected }}</p>
<p>...more child nodes</p>
</div>When the component's selected state changes, a large amount of VNodes will be created even though most of the items remained exactly the same. The v-memo usage here is essentially saying "only update this item if it went from non-selected to selected, or the other way around". This allows every unaffected item to reuse its previous VNode and skip diffing entirely. Note we don't need to include item.id in the memo dependency array here since Vue automatically infers it from the item's :key.
:::warning When using v-memo with v-for, make sure they are used on the same element. `v-memo` does not work inside `v-for`. :::
v-memo can also be used on components to manually prevent unwanted updates in certain edge cases where the child component update check has been de-optimized. But again, it is the developer's responsibility to specify correct dependency arrays to avoid skipping necessary updates.
- See also
- v-once
v-cloak {#v-cloak}
Used to hide un-compiled template until it is ready.
- Does not expect expression
- Details
This directive is only needed in no-build-step setups.
When using in-DOM templates, there can be a "flash of un-compiled templates": the user may see raw mustache tags until the mounted component replaces them with rendered content.
v-cloak will remain on the element until the associated component instance is mounted. Combined with CSS rules such as [v-cloak] { display: none }, it can be used to hide the raw templates until the component is ready.
- Example
[v-cloak] {
display: none;
} <div v-cloak>
{{ message }}
</div>The <div> will not be visible until the compilation is done.
Built-in Special Attributes {#built-in-special-attributes}
key {#key}
The key special attribute is primarily used as a hint for Vue's virtual DOM algorithm to identify vnodes when diffing the new list of nodes against the old list.
- Expects:
number | string | symbol
- Details
Without keys, Vue uses an algorithm that minimizes element movement and tries to patch/reuse elements of the same type in-place as much as possible. With keys, it will reorder elements based on the order change of keys, and elements with keys that are no longer present will always be removed / destroyed.
Children of the same common parent must have unique keys. Duplicate keys will cause render errors.
The most common use case is combined with v-for:
<ul>
<li v-for="item in items" :key="item.id">...</li>
</ul>It can also be used to force replacement of an element/component instead of reusing it. This can be useful when you want to:
- Properly trigger lifecycle hooks of a component
- Trigger transitions
For example:
<transition>
<span :key="text">{{ text }}</span>
</transition>When text changes, the <span> will always be replaced instead of patched, so a transition will be triggered.
ref {#ref}
Denotes a template ref.
- Expects:
string | Function
- Details
ref is used to register a reference to an element or a child component.
In Options API, the reference will be registered under the component's this.$refs object:
<!-- stored as this.$refs.p -->
<p ref="p">hello</p>In Composition API, the reference will be stored in a ref with matching name:
<script setup>
import { useTemplateRef } from 'vue'
const pRef = useTemplateRef('p')
</script>
<template>
<p ref="p">hello</p>
</template>If used on a plain DOM element, the reference will be that element; if used on a child component, the reference will be the child component instance.
Alternatively ref can accept a function value which provides full control over where to store the reference:
<ChildComponent :ref="(el) => child = el" />An important note about the ref registration timing: because the refs themselves are created as a result of the render function, you must wait until the component is mounted before accessing them.
this.$refs is also non-reactive, therefore you should not attempt to use it in templates for data-binding.
- See also
- Guide - Template Refs
- Guide - Typing Template Refs <sup class="vt-badge ts" />
- Guide - Typing Component Template Refs <sup class="vt-badge ts" />
is {#is}
Used for binding dynamic components.
- Expects:
string | Component
- Usage on native elements
- Only supported in 3.1+
When the is attribute is used on a native HTML element, it will be interpreted as a Customized built-in element, which is a native web platform feature.
There is, however, a use case where you may need Vue to replace a native element with a Vue component, as explained in in-DOM Template Parsing Caveats. You can prefix the value of the is attribute with vue: so that Vue will render the element as a Vue component instead:
<table>
<tr is="vue:my-row-component"></tr>
</table>- See also
<ApiIndex />
Community Newsletters {#community-newsletters}
There are many great newsletters / Vue-dedicated blogs from the community bringing you latest news and happenings in the Vue ecosystem. Here is a non-exhaustive list of active ones that we have come across:
- Vue.js Feed
- Michael Thiessen
- Jakub Andrzejewski
- Weekly Vue News
- Vue.js Developers Newsletter
If you know a great one that isn't already included, please submit a pull request using the link below!
<ThemePage />
<ClientOnly> <ExampleRepl /> </ClientOnly>