**Result**
Count is: 0
The above example demonstrates the two core features of Vue:
* **Declarative Rendering**: Vue extends standard HTML with a template syntax that allows us to declaratively describe HTML output based on JavaScript state.
* **Reactivity**: Vue automatically tracks JavaScript state changes and efficiently updates the DOM when changes happen.
You may already have questions - don't worry. We will cover every little detail in the rest of the documentation. For now, please read along so you can have a high-level understanding of what Vue offers.
Prerequisites
The rest of the documentation assumes basic familiarity with HTML, CSS, and JavaScript. If you are totally new to frontend development, it might not be the best idea to jump right into a framework as your first step - grasp the basics and then come back! You can check your knowledge level with these overviews for [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript)
, [HTML](https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML)
and [CSS](https://developer.mozilla.org/en-US/docs/Learn/CSS/First_steps)
if needed. Prior experience with other frameworks helps, but is not required.
The Progressive Framework [](#the-progressive-framework)
----------------------------------------------------------
Vue is a framework and ecosystem that covers most of the common features needed in frontend development. But the web is extremely diverse - the things we build on the web may vary drastically in form and scale. With that in mind, Vue is designed to be flexible and incrementally adoptable. Depending on your use case, Vue can be used in different ways:
* Enhancing static HTML without a build step
* Embedding as Web Components on any page
* Single-Page Application (SPA)
* Fullstack / Server-Side Rendering (SSR)
* Jamstack / Static Site Generation (SSG)
* Targeting desktop, mobile, WebGL, and even the terminal
If you find these concepts intimidating, don't worry! The tutorial and guide only require basic HTML and JavaScript knowledge, and you should be able to follow along without being an expert in any of these.
If you are an experienced developer interested in how to best integrate Vue into your stack, or you are curious about what these terms mean, we discuss them in more detail in [Ways of Using Vue](/guide/extras/ways-of-using-vue)
.
Despite the flexibility, the core knowledge about how Vue works is shared across all these use cases. Even if you are just a beginner now, the knowledge gained along the way will stay useful as you grow to tackle more ambitious goals in the future. If you are a veteran, you can pick the optimal way to leverage Vue based on the problems you are trying to solve, while retaining the same productivity. This is why we call Vue "The Progressive Framework": it's a framework that can grow with you and adapt to your needs.
Single-File Components [](#single-file-components)
----------------------------------------------------
In most build-tool-enabled Vue projects, we author Vue components using an HTML-like file format called **Single-File Component** (also known as `*.vue` files, abbreviated as **SFC**). A Vue SFC, as the name suggests, encapsulates the component's logic (JavaScript), template (HTML), and styles (CSS) in a single file. Here's the previous example, written in SFC format:
vue
vue
SFC is a defining feature of Vue and is the recommended way to author Vue components **if** your use case warrants a build setup. You can learn more about the [how and why of SFC](/guide/scaling-up/sfc)
in its dedicated section - but for now, just know that Vue will handle all the build tools setup for you.
API Styles [](#api-styles)
----------------------------
Vue components can be authored in two different API styles: **Options API** and **Composition API**.
### Options API [](#options-api)
With Options API, we define a component's logic using an object of options such as `data`, `methods`, and `mounted`. Properties defined by options are exposed on `this` inside functions, which points to the component instance:
vue
[Try it in the Playground](https://play.vuejs.org/#eNptkMFqxCAQhl9lkB522ZL0HNKlpa/Qo4e1ZpLIGhUdl5bgu9es2eSyIMio833zO7NP56pbRNawNkivHJ25wV9nPUGHvYiaYOYGoK7Bo5CkbgiBBOFy2AkSh2N5APmeojePCkDaaKiBt1KnZUuv3Ky0PppMsyYAjYJgigu0oEGYDsirYUAP0WULhqVrQhptF5qHQhnpcUJD+wyQaSpUd/Xp9NysVY/yT2qE0dprIS/vsds5Mg9mNVbaDofL94jZpUgJXUKBCvAy76ZUXY53CTd5tfX2k7kgnJzOCXIF0P5EImvgQ2olr++cbRE4O3+t6JxvXj0ptXVpye1tvbFY+ge/NJZt)
### Composition API [](#composition-api)
With Composition API, we define a component's logic using imported API functions. In SFCs, Composition API is typically used with [`
[Try it in the Playground](https://play.vuejs.org/#eNpNkMFqwzAQRH9lMYU4pNg9Bye09NxbjzrEVda2iLwS0spQjP69a+yYHnRYad7MaOfiw/tqSliciybqYDxDRE7+qsiM3gWGGQJ2r+DoyyVivEOGLrgRDkIdFCmqa1G0ms2EELllVKQdRQa9AHBZ+PLtuEm7RCKVd+ChZRjTQqwctHQHDqbvMUDyd7mKip4AGNIBRyQujzArgtW/mlqb8HRSlLcEazrUv9oiDM49xGGvXgp5uT5his5iZV1f3r4HFHvDprVbaxPhZf4XkKub/CDLaep1T7IhGRhHb6WoTADNT2KWpu/aGv24qGKvrIrr5+Z7hnneQnJu6hURvKl3ryL/ARrVkuI=)
### Which to Choose? [](#which-to-choose)
Both API styles are fully capable of covering common use cases. They are different interfaces powered by the exact same underlying system. In fact, the Options API is implemented on top of the Composition API! The fundamental concepts and knowledge about Vue are shared across the two styles.
The Options API is centered around the concept of a "component instance" (`this` as seen in the example), which typically aligns better with a class-based mental model for users coming from OOP language backgrounds. It is also more beginner-friendly by abstracting away the reactivity details and enforcing code organization via option groups.
The Composition API is centered around declaring reactive state variables directly in a function scope and composing state from multiple functions together to handle complexity. It is more free-form and requires an understanding of how reactivity works in Vue to be used effectively. In return, its flexibility enables more powerful patterns for organizing and reusing logic.
You can learn more about the comparison between the two styles and the potential benefits of Composition API in the [Composition API FAQ](/guide/extras/composition-api-faq)
.
If you are new to Vue, here's our general recommendation:
* For learning purposes, go with the style that looks easier to understand to you. Again, most of the core concepts are shared between the two styles. You can always pick up the other style later.
* For production use:
* Go with Options API if you are not using build tools, or plan to use Vue primarily in low-complexity scenarios, e.g. progressive enhancement.
* Go with Composition API + Single-File Components if you plan to build full applications with Vue.
You don't have to commit to only one style during the learning phase. The rest of the documentation will provide code samples in both styles where applicable, and you can toggle between them at any time using the **API Preference switches** at the top of the left sidebar.
Still Got Questions? [](#still-got-questions)
-----------------------------------------------
Check out our [FAQ](/about/faq)
.
Pick Your Learning Path [](#pick-your-learning-path)
------------------------------------------------------
Different developers have different learning styles. Feel free to pick a learning path that suits your preference - although we do recommend going over all of the content, if possible!
[Try the Tutorial\
\
For those who prefer learning things hands-on.](/tutorial/)
[Read the Guide\
\
The guide walks you through every aspect of the framework in full detail.](/guide/quick-start)
[Check out the Examples\
\
Explore examples of core features and common UI tasks.](/examples/)
[Edit this page on GitHub](https://github.com/vuejs/docs/edit/main/src/guide/introduction.md)
Introduction has loaded
---
# Tutorial | Vue.js
Tutorial has loaded
---
# Examples | Vue.js
Examples has loaded
---
# Quick Start | Vue.js
On this page
Quick Start [](#quick-start)
==============================
Try Vue Online [](#try-vue-online)
------------------------------------
* To quickly get a taste of Vue, you can try it directly in our [Playground](https://play.vuejs.org/#eNo9jcEKwjAMhl/lt5fpQYfXUQfefAMvvRQbddC1pUuHUPrudg4HIcmXjyRZXEM4zYlEJ+T0iEPgXjn6BB8Zhp46WUZWDjCa9f6w9kAkTtH9CRinV4fmRtZ63H20Ztesqiylphqy3R5UYBqD1UyVAPk+9zkvV1CKbCv9poMLiTEfR2/IXpSoXomqZLtti/IFwVtA9A==)
.
* If you prefer a plain HTML setup without any build steps, you can use this [JSFiddle](https://jsfiddle.net/yyx990803/2ke1ab0z/)
as your starting point.
* If you are already familiar with Node.js and the concept of build tools, you can also try a complete build setup right within your browser on [StackBlitz](https://vite.new/vue)
.
Creating a Vue Application [](#creating-a-vue-application)
------------------------------------------------------------
Prerequisites
* Familiarity with the command line
* Install [Node.js](https://nodejs.org/)
version 18.3 or higher
In this section we will introduce how to scaffold a Vue [Single Page Application](/guide/extras/ways-of-using-vue#single-page-application-spa)
on your local machine. The created project will be using a build setup based on [Vite](https://vitejs.dev)
and allow us to use Vue [Single-File Components](/guide/scaling-up/sfc)
(SFCs).
Make sure you have an up-to-date version of [Node.js](https://nodejs.org/)
installed and your current working directory is the one where you intend to create a project. Run the following command in your command line (without the `$` sign):
npm
pnpm
yarn
bun
sh
$ npm create vue@latest
sh
$ pnpm create vue@latest
sh
# For Yarn (v1+)
$ yarn create vue
# For Yarn Modern (v2+)
$ yarn create vue@latest
# For Yarn ^v4.11
$ yarn dlx create-vue@latest
sh
$ bun create vue@latest
This command will install and execute [create-vue](https://github.com/vuejs/create-vue)
, the official Vue project scaffolding tool. You will be presented with prompts for several optional features such as TypeScript and testing support:
✔ Project name: …
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit testing? … No / Yes
✔ Add an End-to-End Testing Solution? … No / Cypress / Nightwatch / Playwright
✔ Add ESLint for code quality? … No / Yes
✔ Add Prettier for code formatting? … No / Yes
✔ Add Vue DevTools 7 extension for debugging? (experimental) … No / Yes
Scaffolding project in ./...
Done.
If you are unsure about an option, simply choose `No` by hitting enter for now. Once the project is created, follow the instructions to install dependencies and start the dev server:
npm
pnpm
yarn
bun
sh
$ cd
$ npm install
$ npm run dev
sh
$ cd
$ pnpm install
$ pnpm run dev
sh
$ cd
$ yarn
$ yarn dev
sh
$ cd
$ bun install
$ bun run dev
You should now have your first Vue project running! Note that the example components in the generated project are written using the [Composition API](/guide/introduction#composition-api)
and `
Here we are using [unpkg](https://unpkg.com/)
, but you can also use any CDN that serves npm packages, for example [jsdelivr](https://www.jsdelivr.com/package/npm/vue)
or [cdnjs](https://cdnjs.com/libraries/vue)
. Of course, you can also download this file and serve it yourself.
When using Vue from a CDN, there is no "build step" involved. This makes the setup a lot simpler, and is suitable for enhancing static HTML or integrating with a backend framework. However, you won't be able to use the Single-File Component (SFC) syntax.
### Using the Global Build [](#using-the-global-build)
The above link loads the _global build_ of Vue, where all top-level APIs are exposed as properties on the global `Vue` object. Here is a full example using the global build:
html
{{ message }}
[CodePen Demo >](https://codepen.io/vuejs-examples/pen/QWJwJLp)
html
{{ message }}
[CodePen Demo >](https://codepen.io/vuejs-examples/pen/eYQpQEG)
TIP
Many of the examples for Composition API throughout the guide will be using the `
html
{{ message }}
Notice that we are using `
{{ message }}
[CodePen Demo >](https://codepen.io/vuejs-examples/pen/wvQKQyM)
html
{{ message }}
[CodePen Demo >](https://codepen.io/vuejs-examples/pen/YzRyRYM)
You can also add entries for other dependencies to the import map - but make sure they point to the ES modules version of the library you intend to use.
Import Maps Browser Support
Import Maps is a relatively new browser feature. Make sure to use a browser within its [support range](https://caniuse.com/import-maps)
. In particular, it is only supported in Safari 16.4+.
Notes on Production Use
The examples so far are using the development build of Vue - if you intend to use Vue from a CDN in production, make sure to check out the [Production Deployment Guide](/guide/best-practices/production-deployment#without-build-tools)
.
While it is possible to use Vue without a build system, an alternative approach to consider is using [`vuejs/petite-vue`](https://github.com/vuejs/petite-vue)
that could better suit the context where [`jquery/jquery`](https://github.com/jquery/jquery)
(in the past) or [`alpinejs/alpine`](https://github.com/alpinejs/alpine)
(in the present) might be used instead.
### Splitting Up the Modules [](#splitting-up-the-modules)
As we dive deeper into the guide, we may need to split our code into separate JavaScript files so that they are easier to manage. For example:
html
js
// my-component.js
export default {
data() {
return { count: 0 }
},
template: `
`
}
If you directly open the above `index.html` in your browser, you will find that it throws an error because ES modules cannot work over the `file://` protocol, which is the protocol the browser uses when you open a local file.
Due to security reasons, ES modules can only work over the `http://` protocol, which is what the browsers use when opening pages on the web. In order for ES modules to work on our local machine, we need to serve the `index.html` over the `http://` protocol, with a local HTTP server.
To start a local HTTP server, first make sure you have [Node.js](https://nodejs.org/en/)
installed, then run `npx serve` from the command line in the same directory where your HTML file is. You can also use any other HTTP server that can serve static files with the correct MIME types.
You may have noticed that the imported component's template is inlined as a JavaScript string. If you are using VS Code, you can install the [es6-string-html](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
extension and prefix the strings with a `/*html*/` comment to get syntax highlighting for them.
Next Steps [](#next-steps)
----------------------------
If you skipped the [Introduction](/guide/introduction)
, we strongly recommend reading it before moving on to the rest of the documentation.
[Continue with the Guide\
\
The guide walks you through every aspect of the framework in full detail.](/guide/essentials/application)
[Try the Tutorial\
\
For those who prefer learning things hands-on.](/tutorial/)
[Check out the Examples\
\
Explore examples of core features and common UI tasks.](/examples/)
[Edit this page on GitHub](https://github.com/vuejs/docs/edit/main/src/guide/quick-start.md)
Quick Start has loaded
---
# Glossary | Vue.js
Glossary [](#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 intended to be _descriptive_ of how terms are commonly used, not a _prescriptive_ specification of how they must be used. Some terms may have slightly different meanings or nuances depending on the surrounding context.
async component [](#async-component)
--------------------------------------
An _async component_ is a wrapper around another component that allows for the wrapped component to be lazy loaded. This is typically used as a way to reduce the size of the built `.js` files, allowing them to be split into smaller chunks that are loaded only when required.
Vue Router has a similar feature for the [lazy loading of route components](https://router.vuejs.org/guide/advanced/lazy-loading.html)
, though this does not use Vue's async components feature.
For more details see:
* [Guide - Async Components](/guide/components/async)
compiler macro [](#compiler-macro)
------------------------------------
A _compiler macro_ is special code that is processed by a compiler and converted into something else. They are effectively a clever form of string replacement.
Vue's [SFC](#single-file-component)
compiler supports various macros, such as `defineProps()`, `defineEmits()` and `defineExpose()`. These macros are intentionally designed to look like normal JavaScript functions so that they can leverage the same parser and type inference tooling around JavaScript / TypeScript. However, they are not actual functions that are run in the browser. These are special strings that the compiler detects and replaces with the real JavaScript code that will actually be run.
Macros have limitations on their use that don't apply to normal JavaScript code. For example, you might think that `const dp = defineProps` would allow you to create an alias for `defineProps`, but it'll actually result in an error. There are also limitations on what values can be passed to `defineProps()`, as the 'arguments' have to be processed by the compiler and not at runtime.
For more details see:
* [`
Has published books:
{{ publishedBooksMessage }}
[Try it in the Playground](https://play.vuejs.org/#eNp1kE9Lw0AQxb/KI5dtoTainkoaaREUoZ5EEONhm0ybYLO77J9CCfnuzta0vdjbzr6Zeb95XbIwZroPlMySzJW2MR6OfDB5oZrWaOvRwZIsfbOnCUrdmuCpQo+N1S0ET4pCFarUynnI4GttMT9PjLpCAUq2NIN41bXCkyYxiZ9rrX/cDF/xDYiPQLjDDRbVXqqSHZ5DUw2tg3zP8lK6pvxHe2DtvSasDs6TPTAT8F2ofhzh0hTygm5pc+I1Yb1rXE3VMsKsyDm5JcY/9Y5GY8xzHI+wnIpVw4nTI/10R2rra+S4xSPEJzkBvvNNs310ztK/RDlLLjy1Zic9cQVkJn+R7gIwxJGlMXiWnZEq77orhH3Pq2NH9DjvTfpfSBSbmA==)
Here we have declared a computed property `publishedBooksMessage`. The `computed()` function expects to be passed a [getter function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#description)
, and the returned value is a **computed ref**. Similar to normal refs, you can access the computed result as `publishedBooksMessage.value`. Computed refs are also auto-unwrapped in templates so you can reference them without `.value` in template expressions.
A computed property automatically tracks its reactive dependencies. Vue is aware that the computation of `publishedBooksMessage` depends on `author.books`, so it will update any bindings that depend on `publishedBooksMessage` when `author.books` changes.
See also: [Typing Computed](/guide/typescript/composition-api#typing-computed)
Computed Caching vs. Methods [](#computed-caching-vs-methods)
---------------------------------------------------------------
You may have noticed we can achieve the same result by invoking a method in the expression:
template
{{ calculateBooksMessage() }}
js
// in component
methods: {
calculateBooksMessage() {
return this.author.books.length > 0 ? 'Yes' : 'No'
}
}
js
// in component
function calculateBooksMessage() {
return author.books.length > 0 ? 'Yes' : 'No'
}
Instead of a computed property, we can define the same function as a method. For the end result, the two approaches are indeed exactly the same. However, the difference is that **computed properties are cached based on their reactive dependencies.** A computed property will only re-evaluate when some of its reactive dependencies have changed. This means as long as `author.books` has not changed, multiple access to `publishedBooksMessage` will immediately return the previously computed result without having to run the getter function again.
This also means the following computed property will never update, because `Date.now()` is not a reactive dependency:
js
computed: {
now() {
return Date.now()
}
}
js
const now = computed(() => Date.now())
In comparison, a method invocation will **always** run the function whenever a re-render happens.
Why do we need caching? Imagine we have an expensive computed property `list`, which requires looping through a huge array and doing a lot of computations. Then we may have other computed properties that in turn depend on `list`. Without caching, we would be executing `list`’s getter many more times than necessary! In cases where you do not want caching, use a method call instead.
Writable Computed [](#writable-computed)
------------------------------------------
Computed properties are by default getter-only. If you attempt to assign a new value to a computed property, you will receive a runtime warning. In the rare cases where you need a "writable" computed property, you can create one by providing both a getter and a setter:
js
export default {
data() {
return {
firstName: 'John',
lastName: 'Doe'
}
},
computed: {
fullName: {
// getter
get() {
return this.firstName + ' ' + this.lastName
},
// setter
set(newValue) {
// Note: we are using destructuring assignment syntax here.
[this.firstName, this.lastName] = newValue.split(' ')
}
}
}
}
Now when you run `this.fullName = 'John Doe'`, the setter will be invoked and `this.firstName` and `this.lastName` will be updated accordingly.
vue
Now when you run `fullName.value = 'John Doe'`, the setter will be invoked and `firstName` and `lastName` will be updated accordingly.
Getting the Previous Value [](#previous)
------------------------------------------
* Only supported in 3.4+
In case you need it, you can get the previous value returned by the computed property accessing the first argument of the getter:
js
export default {
data() {
return {
count: 2
}
},
computed: {
// This computed will return the value of count when it's less or equal to 3.
// When count is >=4, the last value that fulfilled our condition will be returned
// instead until count is less or equal to 3
alwaysSmall(previous) {
if (this.count <= 3) {
return this.count
}
return previous
}
}
}
vue
In case you're using a writable computed:
js
export default {
data() {
return {
count: 2
}
},
computed: {
alwaysSmall: {
get(previous) {
if (this.count <= 3) {
return this.count
}
return previous;
},
set(newValue) {
this.count = newValue * 2
}
}
}
}
vue
Best Practices [](#best-practices)
------------------------------------
### Getters should be side-effect free [](#getters-should-be-side-effect-free)
It is important to remember that computed getter functions should only perform pure computation and be free of side effects. For example, **don't mutate other state, make async requests, or mutate the DOM inside a computed getter!** Think of a computed property as declaratively describing how to derive a value based on other values - its only responsibility should be computing and returning that value. Later in the guide we will discuss how we can perform side effects in reaction to state changes with [watchers](/guide/essentials/watchers)
.
### Avoid mutating computed value [](#avoid-mutating-computed-value)
The returned value from a computed property is derived state. Think of it as a temporary snapshot - every time the source state changes, a new snapshot is created. It does not make sense to mutate a snapshot, so a computed return value should be treated as read-only and never be mutated - instead, update the source state it depends on to trigger new computations.
[Edit this page on GitHub](https://github.com/vuejs/docs/edit/main/src/guide/essentials/computed.md)
Computed Properties has loaded
---
# Reactivity Fundamentals | Vue.js
On this page
Reactivity Fundamentals [](#reactivity-fundamentals)
======================================================
API Preference
This page and many other chapters later in the guide contain different content for the Options API and the Composition API. Your current preference is Options APIComposition API. You can toggle between the API styles using the "API Preference" switches at the top of the left sidebar.
Declaring Reactive State [](#declaring-reactive-state)
--------------------------------------------------------
With the Options API, we use the `data` option to declare reactive state of a component. The option value should be a function that returns an object. Vue will call the function when creating a new component instance, and wrap the returned object in its reactivity system. Any top-level properties of this object are proxied on the component instance (`this` in methods and lifecycle hooks):
js
export default {
data() {
return {
count: 1
}
},
// `mounted` is a lifecycle hook which we will explain later
mounted() {
// `this` refers to the component instance.
console.log(this.count) // => 1
// data can be mutated as well
this.count = 2
}
}
[Try it in the Playground](https://play.vuejs.org/#eNpFUNFqhDAQ/JXBpzsoHu2j3B2U/oYPpnGtoetGkrW2iP/eRFsPApthd2Zndilex7H8mqioimu0wY16r4W+Rx8ULXVmYsVSC9AaNafz/gcC6RTkHwHWT6IVnne85rI+1ZLr5YJmyG1qG7gIA3Yd2R/LhN77T8y9sz1mwuyYkXazcQI2SiHz/7iP3VlQexeb5KKjEKEe2lPyMIxeSBROohqxVO4E6yV6ppL9xykTy83tOQvd7tnzoZtDwhrBO2GYNFloYWLyxrzPPOi44WWLWUt618txvASUhhRCKSHgbZt2scKy7HfCujGOqWL9BVfOgyI=)
These instance properties are only added when the instance is first created, so you need to ensure they are all present in the object returned by the `data` function. Where necessary, use `null`, `undefined` or some other placeholder value for properties where the desired value isn't yet available.
It is possible to add a new property directly to `this` without including it in `data`. However, properties added this way will not be able to trigger reactive updates.
Vue uses a `$` prefix when exposing its own built-in APIs via the component instance. It also reserves the prefix `_` for internal properties. You should avoid using names for top-level `data` properties that start with either of these characters.
### Reactive Proxy vs. Original [](#reactive-proxy-vs-original)
In Vue 3, data is made reactive by leveraging [JavaScript Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
. Users coming from Vue 2 should be aware of the following edge case:
js
export default {
data() {
return {
someObject: {}
}
},
mounted() {
const newObject = {}
this.someObject = newObject
console.log(newObject === this.someObject) // false
}
}
When you access `this.someObject` after assigning it, the value is a reactive proxy of the original `newObject`. **Unlike in Vue 2, the original `newObject` is left intact and will not be made reactive: make sure to always access reactive state as a property of `this`.**
Declaring Reactive State [](#declaring-reactive-state-1)
----------------------------------------------------------
### `ref()` [](#ref)
In Composition API, the recommended way to declare reactive state is using the [`ref()`](/api/reactivity-core#ref)
function:
js
import { ref } from 'vue'
const count = ref(0)
`ref()` takes the argument and returns it wrapped within a ref object with a `.value` property:
js
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
> See also: [Typing Refs](/guide/typescript/composition-api#typing-ref)
To access refs in a component's template, declare and return them from a component's `setup()` function:
js
import { ref } from 'vue'
export default {
// `setup` is a special hook dedicated for the Composition API.
setup() {
const count = ref(0)
// expose the ref to the template
return {
count
}
}
}
template
{{ count }}
Notice that we did **not** need to append `.value` when using the ref in the template. For convenience, refs are automatically unwrapped when used inside templates (with a few [caveats](#caveat-when-unwrapping-in-templates)
).
You can also mutate a ref directly in event handlers:
template
For more complex logic, we can declare functions that mutate refs in the same scope and expose them as methods alongside the state:
js
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
function increment() {
// .value is needed in JavaScript
count.value++
}
// don't forget to expose the function as well.
return {
count,
increment
}
}
}
Exposed methods can then be used as event handlers:
template
Here's the example live on [Codepen](https://codepen.io/vuejs-examples/pen/WNYbaqo)
, without using any build tools.
### `
[Try it in the Playground](https://play.vuejs.org/#eNo9jUEKgzAQRa8yZKMiaNcllvYe2dgwQqiZhDhxE3L3jrW4/DPvv1/UK8Zhz6juSm82uciwIef4MOR8DImhQMIFKiwpeGgEbQwZsoE2BhsyMUwH0d66475ksuwCgSOb0CNx20ExBCc77POase8NVUN6PBdlSwKjj+vMKAlAvzOzWJ52dfYzGXXpjPoBAKX856uopDGeFfnq8XKp+gWq4FAi)
Top-level imports, variables and functions declared in `
Ask a yes/no question:
{{ answer }}
[Try it in the Playground](https://play.vuejs.org/#eNp9U8Fy0zAQ/ZVFF9tDah96C2mZ0umhHKBAj7oIe52oUSQjyXEyGf87KytyoDC9JPa+p+e3b1cndtd15b5HtmQrV1vZeXDo++6Wa7nrjPVwAovtAgbh6w2M0Fqzg4xOZFxzXRvtPPzq0XlpNNwEbp5lRUKEdgPaVP925jnoXS+UOgKxvJAaxEVjJ+y2hA9XxUVFGdFIvT7LtEI5JIzrqjrbGozdOmikxdqTKqmIQOV6gvOkvQDhjrqGXOOQvCzAqCa9FHBzCyeuAWT7F6uUulZ9gy7PPmZFETmQjJV7oXoke972GJHY+Axkzxupt4FalhRcYHh7TDIQcqA+LTriikFIDy0G59nG+84tq+qITpty8G0lOhmSiedefSaPZ0mnfHFG50VRRkbkj1BPceVorbFzF/+6fQj4O7g3vWpAm6Ao6JzfINw9PZaQwXuYNJJuK/U0z1nxdTLT0M7s8Ec/I3WxquLS0brRi8ddp4RHegNYhR0M/Du3pXFSAJU285osI7aSuus97K92pkF1w1nCOYNlI534qbCh8tkOVasoXkV1+sjplLZ0HGN5Vc1G2IJ5R8Np5XpKlK7J1CJntdl1UqH92k0bzdkyNc8ZRWGGz1MtbMQi1esN1tv/1F/cIdQ4e6LJod0jZzPmhV2jj/DDjy94oOcZpK57Rew3wO/ojOpjJIH2qdcN2f6DN7l9nC47RfTsHg4etUtNpZUeJz5ndPPv32j9Yve6vE6DZuNvu1R2Tg==)
### Watch Source Types [](#watch-source-types)
`watch`'s first argument can be different types of reactive "sources": it can be a ref (including computed refs), a reactive object, a [getter function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#description)
, or an array of multiple sources:
js
const x = ref(0)
const y = ref(0)
// single ref
watch(x, (newX) => {
console.log(`x is ${newX}`)
})
// getter
watch(
() => x.value + y.value,
(sum) => {
console.log(`sum of x + y is: ${sum}`)
}
)
// array of multiple sources
watch([x, () => y.value], ([newX, newY]) => {
console.log(`x is ${newX} and y is ${newY}`)
})
Do note that you can't watch a property of a reactive object like this:
js
const obj = reactive({ count: 0 })
// this won't work because we are passing a number to watch()
watch(obj.count, (count) => {
console.log(`Count is: ${count}`)
})
Instead, use a getter:
js
// instead, use a getter:
watch(
() => obj.count,
(count) => {
console.log(`Count is: ${count}`)
}
)
Deep Watchers [](#deep-watchers)
----------------------------------
`watch` is shallow by default: the callback will only trigger when the watched property has been assigned a new value - it won't trigger on nested property changes. If you want the callback to fire on all nested mutations, you need to use a deep watcher:
js
export default {
watch: {
someObject: {
handler(newValue, oldValue) {
// Note: `newValue` will be equal to `oldValue` here
// on nested mutations as long as the object itself
// hasn't been replaced.
},
deep: true
}
}
}
When you call `watch()` directly on a reactive object, it will implicitly create a deep watcher - the callback will be triggered on all nested mutations:
js
const obj = reactive({ count: 0 })
watch(obj, (newValue, oldValue) => {
// fires on nested property mutations
// Note: `newValue` will be equal to `oldValue` here
// because they both point to the same object!
})
obj.count++
This should be differentiated with a getter that returns a reactive object - in the latter case, the callback will only fire if the getter returns a different object:
js
watch(
() => state.someObject,
() => {
// fires only when state.someObject is replaced
}
)
You can, however, force the second case into a deep watcher by explicitly using the `deep` option:
js
watch(
() => state.someObject,
(newValue, oldValue) => {
// Note: `newValue` will be equal to `oldValue` here
// *unless* state.someObject has been replaced
},
{ deep: true }
)
In Vue 3.5+, the `deep` option can also be a number indicating the max traversal depth - i.e. how many levels should Vue traverse an object's nested properties.
Use with Caution
Deep watch requires traversing all nested properties in the watched object, and can be expensive when used on large data structures. Use it only when necessary and beware of the performance implications.
Eager Watchers [](#eager-watchers)
------------------------------------
`watch` is lazy by default: the callback won't be called until the watched source has changed. But in some cases we may want the same callback logic to be run eagerly - for example, we may want to fetch some initial data, and then re-fetch the data whenever relevant state changes.
We can force a watcher's callback to be executed immediately by declaring it using an object with a `handler` function and the `immediate: true` option:
js
export default {
// ...
watch: {
question: {
handler(newQuestion) {
// this will be run immediately on component creation.
},
// force eager callback execution
immediate: true
}
}
// ...
}
The initial execution of the handler function will happen just before the `created` hook. Vue will have already processed the `data`, `computed`, and `methods` options, so those properties will be available on the first invocation.
We can force a watcher's callback to be executed immediately by passing the `immediate: true` option:
js
watch(
source,
(newValue, oldValue) => {
// executed immediately, then again when `source` changes
},
{ immediate: true }
)
Once Watchers [](#once-watchers)
----------------------------------
* Only supported in 3.4+
Watcher's callback will execute whenever the watched source changes. If you want the callback to trigger only once when the source changes, use the `once: true` option.
js
export default {
watch: {
source: {
handler(newValue, oldValue) {
// when `source` changes, triggers only once
},
once: true
}
}
}
js
watch(
source,
(newValue, oldValue) => {
// when `source` changes, triggers only once
},
{ once: true }
)
`watchEffect()` [](#watcheffect)
----------------------------------
It is common for the watcher callback to use exactly the same reactive state as the source. For example, consider the following code, which uses a watcher to load a remote resource whenever the `todoId` ref changes:
js
const todoId = ref(1)
const data = ref(null)
watch(
todoId,
async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
},
{ immediate: true }
)
In particular, notice how the watcher uses `todoId` twice, once as the source and then again inside the callback.
This can be simplified with [`watchEffect()`](/api/reactivity-core#watcheffect)
. `watchEffect()` allows us to track the callback's reactive dependencies automatically. The watcher above can be rewritten as:
js
watchEffect(async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
})
Here, the callback will run immediately, there's no need to specify `immediate: true`. During its execution, it will automatically track `todoId.value` as a dependency (similar to computed properties). Whenever `todoId.value` changes, the callback will be run again. With `watchEffect()`, we no longer need to pass `todoId` explicitly as the source value.
You can check out [this example](/examples/#fetching-data)
of `watchEffect()` and reactive data-fetching in action.
For examples like these, with only one dependency, the benefit of `watchEffect()` is relatively small. But for watchers that have multiple dependencies, using `watchEffect()` removes the burden of having to maintain the list of dependencies manually. In addition, if you need to watch several properties in a nested data structure, `watchEffect()` may prove more efficient than a deep watcher, as it will only track the properties that are used in the callback, rather than recursively tracking all of them.
TIP
`watchEffect` only tracks dependencies during its **synchronous** execution. When using it with an async callback, only properties accessed before the first `await` tick will be tracked.
### `watch` vs. `watchEffect` [](#watch-vs-watcheffect)
`watch` and `watchEffect` both allow us to reactively perform side effects. Their main difference is the way they track their reactive dependencies:
* `watch` only tracks the explicitly watched source. It won't track anything accessed inside the callback. In addition, the callback only triggers when the source has actually changed. `watch` separates dependency tracking from the side effect, giving us more precise control over when the callback should fire.
* `watchEffect`, on the other hand, combines dependency tracking and side effect into one phase. It automatically tracks every reactive property accessed during its synchronous execution. This is more convenient and typically results in terser code, but makes its reactive dependencies less explicit.
Side Effect Cleanup [](#side-effect-cleanup)
----------------------------------------------
Sometimes we may perform side effects, e.g. asynchronous requests, in a watcher:
js
watch(id, (newId) => {
fetch(`/api/${newId}`).then(() => {
// callback logic
})
})
js
export default {
watch: {
id(newId) {
fetch(`/api/${newId}`).then(() => {
// callback logic
})
}
}
}
But what if `id` changes before the request completes? When the previous request completes, it will still fire the callback with an ID value that is already stale. Ideally, we want to be able to cancel the stale request when `id` changes to a new value.
We can use the [`onWatcherCleanup()`](/api/reactivity-core#onwatchercleanup)
API to register a cleanup function that will be called when the watcher is invalidated and is about to re-run:
js
import { watch, onWatcherCleanup } from 'vue'
watch(id, (newId) => {
const controller = new AbortController()
fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
// callback logic
})
onWatcherCleanup(() => {
// abort stale request
controller.abort()
})
})
js
import { onWatcherCleanup } from 'vue'
export default {
watch: {
id(newId) {
const controller = new AbortController()
fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
// callback logic
})
onWatcherCleanup(() => {
// abort stale request
controller.abort()
})
}
}
}
Note that `onWatcherCleanup` is only supported in Vue 3.5+ and must be called during the synchronous execution of a `watchEffect` effect function or `watch` callback function: you cannot call it after an `await` statement in an async function.
Alternatively, an `onCleanup` function is also passed to watcher callbacks as the 3rd argument, and to the `watchEffect` effect function as the first argument:
js
watch(id, (newId, oldId, onCleanup) => {
// ...
onCleanup(() => {
// cleanup logic
})
})
watchEffect((onCleanup) => {
// ...
onCleanup(() => {
// cleanup logic
})
})
js
export default {
watch: {
id(newId, oldId, onCleanup) {
// ...
onCleanup(() => {
// cleanup logic
})
}
}
}
This works in versions before 3.5. In addition, `onCleanup` passed via function argument is bound to the watcher instance so it is not subject to the synchronously constraint of `onWatcherCleanup`.
Callback Flush Timing [](#callback-flush-timing)
--------------------------------------------------
When you mutate reactive state, it may trigger both Vue component updates and watcher callbacks created by you.
Similar to component updates, user-created watcher callbacks are batched to avoid duplicate invocations. For example, we probably don't want a watcher to fire a thousand times if we synchronously push a thousand items into an array being watched.
By default, a watcher's callback is called **after** parent component updates (if any), and **before** the owner component's DOM updates. This means if you attempt to access the owner component's own DOM inside a watcher callback, the DOM will be in a pre-update state.
### Post Watchers [](#post-watchers)
If you want to access the owner component's DOM in a watcher callback **after** Vue has updated it, you need to specify the `flush: 'post'` option:
js
export default {
// ...
watch: {
key: {
handler() {},
flush: 'post'
}
}
}
js
watch(source, callback, {
flush: 'post'
})
watchEffect(callback, {
flush: 'post'
})
Post-flush `watchEffect()` also has a convenience alias, `watchPostEffect()`:
js
import { watchPostEffect } from 'vue'
watchPostEffect(() => {
/* executed after Vue updates */
})
### Sync Watchers [](#sync-watchers)
It's also possible to create a watcher that fires synchronously, before any Vue-managed updates:
js
export default {
// ...
watch: {
key: {
handler() {},
flush: 'sync'
}
}
}
js
watch(source, callback, {
flush: 'sync'
})
watchEffect(callback, {
flush: 'sync'
})
Sync `watchEffect()` also has a convenience alias, `watchSyncEffect()`:
js
import { watchSyncEffect } from 'vue'
watchSyncEffect(() => {
/* executed synchronously upon reactive data change */
})
Use with Caution
Sync watchers do not have batching and triggers every time a reactive mutation is detected. It's ok to use them to watch simple boolean values, but avoid using them on data sources that might be synchronously mutated many times, e.g. arrays.
`this.$watch()` [](#this-watch)
---------------------------------
It's also possible to imperatively create watchers using the [`$watch()` instance method](/api/component-instance#watch)
:
js
export default {
created() {
this.$watch('question', (newQuestion) => {
// ...
})
}
}
This is useful when you need to conditionally set up a watcher, or only watch something in response to user interaction. It also allows you to stop the watcher early.
Stopping a Watcher [](#stopping-a-watcher)
--------------------------------------------
Watchers declared using the `watch` option or the `$watch()` instance method are automatically stopped when the owner component is unmounted, so in most cases you don't need to worry about stopping the watcher yourself.
In the rare case where you need to stop a watcher before the owner component unmounts, the `$watch()` API returns a function for that:
js
const unwatch = this.$watch('foo', callback)
// ...when the watcher is no longer needed:
unwatch()
Watchers declared synchronously inside `setup()` or `
To manually stop a watcher, use the returned handle function. This works for both `watch` and `watchEffect`:
js
const unwatch = watchEffect(() => {})
// ...later, when no longer needed
unwatch()
Note that there should be very few cases where you need to create watchers asynchronously, and synchronous creation should be preferred whenever possible. If you need to wait for some async data, you can make your watch logic conditional instead:
js
// data to be loaded asynchronously
const data = ref(null)
watchEffect(() => {
if (data.value) {
// do something when data is loaded
}
})
[Edit this page on GitHub](https://github.com/vuejs/docs/edit/main/src/guide/essentials/watchers.md)
Watchers has loaded
---
# Template Refs | Vue.js
On this page
Template Refs [](#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 access to the underlying DOM elements. To achieve this, we can use the special `ref` attribute:
template
`ref` is a special attribute, similar to the `key` attribute discussed in the `v-for` chapter. It allows us to obtain a direct reference to a specific DOM element or child component instance after it's mounted. This may be useful when you want to, for example, programmatically focus an input on component mount, or initialize a 3rd party library on an element.
Accessing the Refs [](#accessing-the-refs)
--------------------------------------------
To obtain the reference with Composition API, we can use the [`useTemplateRef()`](/api/composition-api-helpers#usetemplateref)
helper:
vue
When using TypeScript, Vue's IDE support and `vue-tsc` will automatically infer the type of `input.value` based on what element or component the matching `ref` attribute is used on.
Usage before 3.5
In versions before 3.5 where `useTemplateRef()` was not introduced, we need to declare a ref with a name that matches the template ref attribute's value:
vue
If not using `
Note that you can only access the ref **after the component is mounted.** If you try to access `$refs.input``input` in a template expression, it will be `undefined``null` on the first render. This is because the element doesn't exist until after the first render!
If you are trying to watch the changes of a template ref, make sure to account for the case where the ref has `null` value:
js
watchEffect(() => {
if (input.value) {
input.value.focus()
} else {
// not mounted yet, or the element was unmounted (e.g. by v-if)
}
})
See also: [Typing Template Refs](/guide/typescript/composition-api#typing-template-refs)
Refs inside `v-for` [](#refs-inside-v-for)
--------------------------------------------
> Requires v3.5 or above
When `ref` is used inside `v-for`, the corresponding ref should contain an Array value, which will be populated with the elements after mount:
vue
{{ item }}
[Try it in the Playground](https://play.vuejs.org/#eNp9UsluwjAQ/ZWRLwQpDepyQoDUIg6t1EWUW91DFAZq6tiWF4oU5d87dtgqVRyyzLw3b+aN3bB7Y4ptQDZkI1dZYTw49MFMuBK10dZDAxZXOQSHC6yNLD3OY6zVsw7K4xJaWFldQ49UelxxVWnlPEhBr3GszT6uc7jJ4fazf4KFx5p0HFH+Kme9CLle4h6bZFkfxhNouAIoJVqfHQSKbSkDFnVpMhEpovC481NNVcr3SaWlZzTovJErCqgydaMIYBRk+tKfFLC9Wmk75iyqg1DJBWfRxT7pONvTAZom2YC23QsMpOg0B0l0NDh2YjnzjpyvxLrYOK1o3ckLZ5WujSBHr8YL2gxnw85lxEop9c9TynkbMD/kqy+svv/Jb9wu5jh7s+jQbpGzI+ZLu0byEuHZ+wvt6Ays9TJIYl8A5+i0DHHGjvYQ1JLGPuOlaR/TpRFqvXCzHR2BO5iKg0Zmm/ic0W2ZXrB+Gve2uEt1dJKs/QXbwePE)
Usage before 3.5
In versions before 3.5 where `useTemplateRef()` was not introduced, we need to declare a ref with a name that matches the template ref attribute's value. The ref should also contain an array value:
vue
{{ item }}
When `ref` is used inside `v-for`, the resulting ref value will be an array containing the corresponding elements:
vue
{{ item }}
[Try it in the Playground](https://play.vuejs.org/#eNpFjk0KwjAQha/yCC4Uaou6kyp4DuOi2KkGYhKSiQildzdNa4WQmTc/37xeXJwr35HEUdTh7pXjszT0cdYzWuqaqBm9NEDbcLPeTDngiaM3PwVoFfiI667AvsDhNpWHMQzF+L9sNEztH3C3JlhNpbaPNT9VKFeeulAqplfY5D1p0qurxVQSqel0w5QUUEedY8q0wnvbWX+SYgRAmWxIiuSzm4tBinkc6HvkuSE7TIBKq4lZZWhdLZfE8AWp4l3T)
It should be noted that the ref array does **not** guarantee the same order as the source array.
Function Refs [](#function-refs)
----------------------------------
Instead of a string key, the `ref` attribute can also be bound to a function, which will be called on each component update and gives you full flexibility on where to store the element reference. The function receives the element reference as the first argument:
template
Note we are using a dynamic `:ref` binding so we can pass it a function instead of a ref name string. When the element is unmounted, the argument will be `null`. You can, of course, use a method instead of an inline function.
Ref on Component [](#ref-on-component)
----------------------------------------
> This section assumes knowledge of [Components](/guide/essentials/component-basics)
> . Feel free to skip it and come back later.
`ref` can also be used on a child component. In this case the reference will be that of a component instance:
vue
Usage before 3.5
vue
vue
If the child component is using Options API or not using `
When a parent gets an instance of this component via template refs, the retrieved instance will be of the shape `{ a: number, b: number }` (refs are automatically unwrapped just like on normal instances).
Note that defineExpose must be called before any await operation. Otherwise, properties and methods exposed after the await operation will not be accessible.
See also: [Typing Component Template Refs](/guide/typescript/composition-api#typing-component-template-refs)
The `expose` option can be used to limit the access to a child instance:
js
export default {
expose: ['publicData', 'publicMethod'],
data() {
return {
publicData: 'foo',
privateData: 'bar'
}
},
methods: {
publicMethod() {
/* ... */
},
privateMethod() {
/* ... */
}
}
}
In the above example, a parent referencing this component via template ref will only be able to access `publicData` and `publicMethod`.
[Edit this page on GitHub](https://github.com/vuejs/docs/edit/main/src/guide/essentials/template-refs.md)
Template Refs has loaded
---
# Components Basics | Vue.js
On this page
Components Basics [](#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 organized into a tree of nested components:

This is very similar to how we nest native HTML elements, but Vue implements its own component model that allows us to encapsulate custom content and logic in each component. Vue also plays nicely with native Web Components. If you are curious about the relationship between Vue Components and native Web Components, [read more here](/guide/extras/web-components)
.
Defining a Component [](#defining-a-component)
------------------------------------------------
When using a build step, we typically define each Vue component in a dedicated file using the `.vue` extension - known as a [Single-File Component](/guide/scaling-up/sfc)
(SFC for short):
vue
vue
When not using a build step, a Vue component can be defined as a plain JavaScript object containing Vue-specific options:
js
export default {
data() {
return {
count: 0
}
},
template: `
`
}
js
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return { count }
},
template: `
`
// Can also target an in-DOM template:
// template: '#my-template-element'
}
The template is inlined as a JavaScript string here, which Vue will compile on the fly. You can also use an ID selector pointing to an element (usually native `` elements) - Vue will use its content as the template source.
The example above defines a single component and exports it as the default export of a `.js` file, but you can use named exports to export multiple components from the same file.
Using a Component [](#using-a-component)
------------------------------------------
TIP
We will be using SFC syntax for the rest of this guide - the concepts around components are the same regardless of whether you are using a build step or not. The [Examples](/examples/)
section shows component usage in both scenarios.
To use a child component, we need to import it in the parent component. Assuming we placed our counter component inside a file called `ButtonCounter.vue`, the component will be exposed as the file's default export:
vue
Here is a child component!
To expose the imported component to our template, we need to [register](/guide/components/registration)
it with the `components` option. The component will then be available as a tag using the key it is registered under.
vue
Here is a child component!
With `
{{ title }}
When a value is passed to a prop attribute, it becomes a property on that component instance. The value of that property is accessible within the template and on the component's `this` context, just like any other component property.
vue
{{ title }}
`defineProps` is a compile-time macro that is only available inside `
vue
This documents all the events that a component emits and optionally [validates them](/guide/components/events#events-validation)
. It also allows Vue to avoid implicitly applying them as native listeners to the child component's root element.
Similar to `defineProps`, `defineEmits` is only usable in `
See also: [Typing Component Emits](/guide/typescript/composition-api#typing-component-emits)
If you are not using `
js
export default {
mounted() {
console.log(`the component is now mounted.`)
}
}
There are also other hooks which will be called at different stages of the instance's lifecycle, with the most commonly used being [`onMounted`](/api/composition-api-lifecycle#onmounted)
, [`onUpdated`](/api/composition-api-lifecycle#onupdated)
, and [`onUnmounted`](/api/composition-api-lifecycle#onunmounted)
.[`mounted`](/api/options-lifecycle#mounted)
, [`updated`](/api/options-lifecycle#updated)
, and [`unmounted`](/api/options-lifecycle#unmounted)
.
All lifecycle hooks are called with their `this` context pointing to the current active instance invoking it. Note this means you should avoid using arrow functions when declaring lifecycle hooks, as you won't be able to access the component instance via `this` if you do so.
When calling `onMounted`, Vue automatically associates the registered callback function with the current active component instance. This requires these hooks to be registered **synchronously** during component setup. For example, do not do this:
js
setTimeout(() => {
onMounted(() => {
// this won't work.
})
}, 100)
Do note this doesn't mean that the call must be placed lexically inside `setup()` or `
In non-`
For each property in the `components` object, the key will be the registered name of the component, while the value will contain the implementation of the component. The above example is using the ES2015 property shorthand and is equivalent to:
js
export default {
components: {
ComponentA: ComponentA
}
// ...
}
Note that **locally registered components are _not_ also available in descendant components**. In this case, `ComponentA` will be made available to the current component only, not any of its child or descendant components.
Component Name Casing [](#component-name-casing)
--------------------------------------------------
Throughout the guide, we are using PascalCase names when registering components. This is because:
1. PascalCase names are valid JavaScript identifiers. This makes it easier to import and register components in JavaScript. It also helps IDEs with auto-completion.
2. `` makes it more obvious that this is a Vue component instead of a native HTML element in templates. It also differentiates Vue components from custom elements (web components).
This is the recommended style when working with SFC or string templates. However, as discussed in [in-DOM Template Parsing Caveats](/guide/essentials/component-basics#in-dom-template-parsing-caveats)
, PascalCase tags are not usable in in-DOM templates.
Luckily, Vue supports resolving kebab-case tags to components registered using PascalCase. This means a component registered as `MyComponent` can be referenced inside a Vue template (or inside an HTML element rendered by Vue) via both `` and ``. This allows us to use the same JavaScript component registration code regardless of template source.
[Edit this page on GitHub](https://github.com/vuejs/docs/edit/main/src/guide/components/registration.md)
Component Registration has loaded
---
# Props | Vue.js
On this page
Props [](#props)
==================
> This page assumes you've already read the [Components Basics](/guide/essentials/component-basics)
> . Read that first if you are new to components.
[Watch a free video lesson on Vue School](https://vueschool.io/lessons/vue-3-reusable-components-with-props?friend=vuejs "Free Vue.js Props Lesson")
Props Declaration [](#props-declaration)
------------------------------------------
Vue components require explicit props declaration so that Vue knows what external props passed to the component should be treated as fallthrough attributes (which will be discussed in [its dedicated section](/guide/components/attrs)
).
In SFCs using `
In non-`
More details: [Typing Component Props](/guide/typescript/composition-api#typing-component-props)
Reactive Props Destructure [](#reactive-props-destructure)
------------------------------------------------------------
Vue's reactivity system tracks state usage based on property access. E.g. when you access `props.foo` in a computed getter or a watcher, the `foo` prop gets tracked as a dependency.
So, given the following code:
js
const { foo } = defineProps(['foo'])
watchEffect(() => {
// runs only once before 3.5
// re-runs when the "foo" prop changes in 3.5+
console.log(foo)
})
In version 3.4 and below, `foo` is an actual constant and will never change. In version 3.5 and above, Vue's compiler automatically prepends `props.` when code in the same `
The `$emit` method that we used in the `` isn't accessible within the `
The `defineEmits()` macro **cannot** be used inside a function, it must be placed directly within `
If you are using TypeScript with `
More details: [Typing Component Emits](/guide/typescript/composition-api#typing-component-emits)
js
export default {
emits: {
submit(payload: { email: string, password: string }) {
// return `true` or `false` to indicate
// validation pass / fail
}
}
}
See also: [Typing Component Emits](/guide/typescript/options-api#typing-component-emits)
Although optional, it is recommended to define all emitted events in order to better document how a component should work. It also allows Vue to exclude known listeners from [fallthrough attributes](/guide/components/attrs#v-on-listener-inheritance)
, avoiding edge cases caused by DOM events manually dispatched by 3rd party code.
TIP
If a native event (e.g., `click`) is defined in the `emits` option, the listener will now only listen to component-emitted `click` events and no longer respond to native `click` events.
Events Validation [](#events-validation)
------------------------------------------
Similar to prop type validation, an emitted event can be validated if it is defined with the object syntax instead of the array syntax.
To add validation, the event is assigned a function that receives the arguments passed to the `this.$emit``emit` call and returns a boolean to indicate whether the event is valid or not.
vue
js
export default {
emits: {
// No validation
click: null,
// Validate submit event
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
},
methods: {
submitForm(email, password) {
this.$emit('submit', { email, password })
}
}
}
[Edit this page on GitHub](https://github.com/vuejs/docs/edit/main/src/guide/components/events.md)
Component Events has loaded
---
# Fallthrough Attributes | Vue.js
On this page
Fallthrough Attributes [](#fallthrough-attributes)
====================================================
> This page assumes you've already read the [Components Basics](/guide/essentials/component-basics)
> . Read that first if you are new to components.
Attribute Inheritance [](#attribute-inheritance)
--------------------------------------------------
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 component's [props](/guide/components/props)
or [emits](/guide/components/events#declaring-emitted-events)
. Common examples of this include `class`, `style`, and `id` attributes.
When a component renders a single root element, fallthrough attributes will be automatically added to the root element's attributes. For example, given a `` component with the following template:
template
And a parent using this component with:
template
The final rendered DOM would be:
html
Here, `` did not declare `class` as an accepted prop. Therefore, `class` is treated as a fallthrough attribute and automatically added to ``'s root element.
### `class` and `style` Merging [](#class-and-style-merging)
If the child component's root element already has existing `class` or `style` attributes, it will be merged with the `class` and `style` values that are inherited from the parent. Suppose we change the template of `` in the previous example to:
template
Then the final rendered DOM would now become:
html
### `v-on` Listener Inheritance [](#v-on-listener-inheritance)
The same rule applies to `v-on` event listeners:
template
The `click` listener will be added to the root element of ``, i.e. the native `