Vue Collate 100121

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 187

Introduction

NOTE

Already know Vue 2 and just want to learn about what's new in Vue 3? Check out the Migration Guide!

What is Vue.js?
Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. Unlike other monolithic frameworks, Vue is
designed from the ground up to be incrementally adoptable. The core library is focused on the view layer only, and is easy to pick up
and integrate with other libraries or existing projects. On the other hand, Vue is also perfectly capable of powering sophisticated Single-
Page Applications when used in combination with modern tooling and supporting libraries .

If you’d like to learn more about Vue before diving in, we created a video walking through the core principles and a sample project.

Watch a free video course on Vue Mastery

Getting Started
Installation

TIP

The official guide assumes intermediate level knowledge of 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 then come back!
Prior experience with other frameworks helps, but is not required.

The easiest way to try out Vue.js is using the Hello World example . Feel free to open it in another tab and follow along as we go
through some basic examples.

The Installation page provides more options of installing Vue. Note: We do notrecommend that beginners start with vue-cli , especially
if you are not yet familiar with Node.js-based build tools.

Declarative Rendering
At the core of Vue.js is a system that enables us to declaratively render data to the DOM using straightforward template syntax:

1 <div id="counter">
2 Counter: {{ counter }}
3 </div>

1 const Counter = {
2 data() {
3 return {
4 counter: 0
5 }
6 }
7 }
8
9 Vue.createApp(Counter).mount('#counter')

We have already created our very first Vue app! This looks pretty similar to rendering a string template, but Vue has done a lot of work
under the hood. The data and the DOM are now linked, and everything is now reactive. How do we know? Take a look at the example
below where counter property increments every second and you will see how rendered DOM changes:

1 const CounterApp = {
2 data() {
3 return {
4 counter: 0
5 }
6 },
7 mounted() {
8 setInterval(() => {
9 this.counter++
10 }, 1000)
11 }
12 }

Counter: 185

Stop timer

In addition to text interpolation, we can also bind element attributes like this:
1 <div id="bind-attribute">
2 <span v-bind:title="message">
3 Hover your mouse over me for a few seconds to see my dynamically bound
4 title!
5 </span>
6 </div>

1 const AttributeBinding = {
2 data() {
3 return {
4 message: 'You loaded this page on ' + new Date().toLocaleString()
5 }
6 }
7 }
8
9 Vue.createApp(AttributeBinding).mount('#bind-attribute')

Here we're encountering something new. The v-bind attribute you're seeing is called a directive. Directives are prefixed with v- to
indicate that they are special attributes provided by Vue, and as you may have guessed, they apply special reactive behavior to the
rendered DOM. Here we are basically saying "keep this element's title attribute up-to-date with the message property on the current
active instance."

Handling User Input


To let users interact with your app, we can use the v-on directive to attach event listeners that invoke methods on our instances:

1 <div id="event-handling">
2 <p>{{ message }}</p>
3 <button v-on:click="reverseMessage">Reverse Message</button>
4 </div>

1 const EventHandling = {
2 data() {
3 return {
4 message: 'Hello Vue.js!'
5 }
6 },
7 methods: {
8 reverseMessage() {
9 this.message = this.message
10 .split('')
11 .reverse()
12 .join('')
13 }
14 }
15 }
16
17 Vue.createApp(EventHandling).mount('#event-handling')

Note that in this method we update the state of our app without touching the DOM - all DOM manipulations are handled by Vue, and the
code you write is focused on the underlying logic.

Vue also provides the v-model directive that makes two-way binding between form input and app state a breeze:

1 <div id="two-way-binding">
2 <p>{{ message }}</p>
3 <input v-model="message" />
4 </div>
1 const TwoWayBinding = {
2 data() {
3 return {
4 message: 'Hello Vue!'
5 }
6 }
7 }
8
9 Vue.createApp(TwoWayBinding).mount('#two-way-binding')

Conditionals and Loops


It's easy to toggle the presence of an element, too:

1 <div id="conditional-rendering">
2 <span v-if="seen">Now you see me</span>
3 </div>

1 const ConditionalRendering = {
2 data() {
3 return {
4 seen: true
5 }
6 }
7 }
8
9 Vue.createApp(ConditionalRendering).mount('#conditional-rendering')
This example demonstrates that we can bind data to not only text and attributes, but also the structure of the DOM. Moreover, Vue also
provides a powerful transition effect system that can automatically apply transition effects when elements are inserted/updated/removed
by Vue.

You can change seen from true to false in the sandbox below to check the effect:

There are quite a few other directives, each with its own special functionality. For example, the v-for directive can be used to display
a list of items using the data from an array:

1 <div id="list-rendering">
2 <ol>
3 <li v-for="todo in todos">
4 {{ todo.text }}
5 </li>
6 </ol>
7 </div>

1 const ListRendering = {
2 data() {
3 return {
4 todos: [
5 { text: 'Learn JavaScript' },
6 { text: 'Learn Vue' },
7 { text: 'Build something awesome' }
8 ]
9 }
10 }
11 }
12
13 Vue.createApp(ListRendering).mount('#list-rendering')
Composing with Components
The component system is another important concept in Vue, because it's an abstraction that allows us to build large-scale applications
composed of small, self-contained, and often reusable components. If we think about it, almost any type of application interface can be
abstracted into a tree of components:

In Vue, a component is essentially an instance with pre-defined options. Registering a component in Vue is straightforward: we create a
component object as we did with App objects and we define it in parent's components option:
1 // Create Vue application
2 const app = Vue.createApp(...)
3
4 // Define a new component called todo-item
5 app.component('todo-item', {
6 template: `<li>This is a todo</li>`
7 })
8
9 // Mount Vue application
10 app.mount(...)

Now you can compose it in another component's template:

1 <ol>
2 <!-- Create an instance of the todo-item component -->
3 <todo-item></todo-item>
4 </ol>

But this would render the same text for every todo, which is not super interesting. We should be able to pass data from the parent scope
into child components. Let's modify the component definition to make it accept a prop:

1 app.component('todo-item', {
2 props: ['todo'],
3 template: `<li>{{ todo.text }}</li>`
4 })

Now we can pass the todo into each repeated component using v-bind :

1 <div id="todo-list-app">
2 <ol>
3 <!--
4 Now we provide each todo-item with the todo object
5 it's representing, so that its content can be dynamic.
6 We also need to provide each component with a "key",
7 which will be explained later.
8 -->
9 <todo-item
10 v-for="item in groceryList"
11 v-bind:todo="item"
12 v-bind:key="item.id"
13 ></todo-item>
14 </ol>
15 </div>

1 const TodoList = {
2 data() {
3 return {
4 groceryList: [
5 { id: 0, text: 'Vegetables' },
6 { id: 1, text: 'Cheese' },
7 { id: 2, text: 'Whatever else humans are supposed to eat' }
8 ]
9 }
10 }
11 }
12
13 const app = Vue.createApp(TodoList)
14
15 app.component('todo-item', {
16 props: ['todo'],
17 template: `<li>{{ todo.text }}</li>`
18 })
19
20 app.mount('#todo-list-app')
This is a contrived example, but we have managed to separate our app into two smaller units, and the child is reasonably well-
decoupled from the parent via the props interface. We can now further improve our <todo-item> component with more complex
template and logic without affecting the parent app.

In a large application, it is necessary to divide the whole app into components to make development manageable. We will talk a lot more
about components later in the guide, but here's an (imaginary) example of what an app's template might look like with components:

1 <div id="app">
2 <app-nav></app-nav>
3 <app-view>
4 <app-sidebar></app-sidebar>
5 <app-content></app-content>
6 </app-view>
7 </div>

Relation to Custom Elements


You may have noticed that Vue components are very similar to Custom Elements, which are part of the Web Components Spec .
That's because Vue's component syntax is loosely modeled after the spec. For example, Vue components implement the Slot API and
the is special attribute. However, there are a few key differences:

1. The Web Components Spec has been finalized but is not natively implemented in every browser. Safari 10.1+, Chrome 54+ and
Firefox 63+ natively support web components. In comparison, Vue components work consistently in all supported browsers (IE11 with
compatibility build and above). When needed, Vue components can also be wrapped inside a native custom element.

2. Vue components provide important features that are not available in plain custom elements, most notably cross-component data flow,
custom event communication and build tool integrations.
Although Vue doesn't use custom elements internally, it has great interoperability when it comes to consuming or distributing as
custom elements. Vue CLI also supports building Vue components that register themselves as native custom elements.

Ready for More?


We've briefly introduced the most basic features of Vue.js core - the rest of this guide will cover them and other advanced features with
much finer details, so make sure to read through it all!
Template Syntax
Vue.js uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying component
instance's data. All Vue.js templates are valid HTML that can be parsed by spec-compliant browsers and HTML parsers.

Under the hood, Vue compiles the templates into Virtual DOM render functions. Combined with the reactivity system, Vue is able to
intelligently figure out the minimal number of components to re-render and apply the minimal amount of DOM manipulations when the
app state changes.

If you are familiar with Virtual DOM concepts and prefer the raw power of JavaScript, you can also directly write render functions instead
of templates, with optional JSX support.

Interpolations

Text
The most basic form of data binding is text interpolation using the "Mustache" syntax (double curly braces):

1 <span>Message: {{ msg }}</span>

The mustache tag will be replaced with the value of the msg property from the corresponding component instance. It will also be
updated whenever the msg property changes.
You can also perform one-time interpolations that do not update on data change by using the v-once directive, but keep in mind this will
also affect any other bindings on the same node:

1 <span v-once>This will never change: {{ msg }}</span>

Raw HTML
The double mustaches interprets the data as plain text, not HTML. In order to output real HTML, you will need to use the v-
html directive:

1 <p>Using mustaches: {{ rawHtml }}</p>


2 <p>Using v-html directive: <span v-html="rawHtml"></span></p>

The contents of the span will be replaced with the value of the rawHtml property, interpreted as plain HTML - data bindings are
ignored. Note that you cannot use v-html to compose template partials, because Vue is not a string-based templating engine. Instead,
components are preferred as the fundamental unit for UI reuse and composition.

TIP

Dynamically rendering arbitrary HTML on your website can be very dangerous because it can easily lead to XSS vulnerabilities
. Only use HTML interpolation on trusted content and never on user-provided content

Attributes
Mustaches cannot be used inside HTML attributes. Instead, use a v-bind directive:
1 <div v-bind:id="dynamicId"></div>

If the bound value is null or undefined then the attribute will not be included on the rendered element.

In the case of boolean attributes, where their mere existence implies true , v-bind works a little differently. For example:

1 <button v-bind:disabled="isButtonDisabled">Button</button>

The disabled attribute will be included if isButtonDisabled has a truthy value. It will also be included if the value is an empty string,
maintaining consistency with <button disabled=""> . For other falsy values the attribute will be omitted.

Using JavaScript Expressions


So far we've only been binding to simple property keys in our templates. But Vue.js actually supports the full power of JavaScript
expressions inside all data bindings:

1 {{ number + 1 }}
2
3 {{ ok ? 'YES' : 'NO' }}
4
5 {{ message.split('').reverse().join('') }}
6
7 <div v-bind:id="'list-' + id"></div>

These expressions will be evaluated as JavaScript in the data scope of the current active instance. One restriction is that each binding
can only contain one single expression, so the following will NOT work:
1 <!-- this is a statement, not an expression: -->
2 {{ var a = 1 }}
3
4 <!-- flow control won't work either, use ternary expressions -->
5 {{ if (ok) { return message } }}

Directives
Directives are special attributes with the v- prefix. Directive attribute values are expected to be a single JavaScript expression (with
the exception of v-for and v-on , which will be discussed later). A directive's job is to reactively apply side effects to the DOM when
the value of its expression changes. Let's review the example we saw in the introduction:

1 <p v-if="seen">Now you see me</p>

Here, the v-if directive would remove/insert the <p> element based on the truthiness of the value of the expression seen .

Arguments
Some directives can take an "argument", denoted by a colon after the directive name. For example, the v-bind directive is used to
reactively update an HTML attribute:

1 <a v-bind:href="url"> ... </a>

Here href is the argument, which tells the v-bind directive to bind the element's href attribute to the value of the expression url .

Another example is the v-on directive, which listens to DOM events:


1 <a v-on:click="doSomething"> ... </a>

Here the argument is the event name to listen to. We will talk about event handling in more detail too.

Dynamic Arguments
It is also possible to use a JavaScript expression in a directive argument by wrapping it with square brackets:

1 <!--
2 Note that there are some constraints to the argument expression, as explained
3 in the "Dynamic Argument Expression Constraints" section below.
4 -->
5 <a v-bind:[attributeName]="url"> ... </a>

Here attributeName will be dynamically evaluated as a JavaScript expression, and its evaluated value will be used as the final value
for the argument. For example, if your component instance has a data property, attributeName , whose value is "href" , then this
binding will be equivalent to v-bind:href .

Similarly, you can use dynamic arguments to bind a handler to a dynamic event name:

1 <a v-on:[eventName]="doSomething"> ... </a>

In this example, when eventName 's value is "focus" , v-on:[eventName] will be equivalent to v-on:focus .

Modifiers
Modifiers are special postfixes denoted by a dot, which indicate that a directive should be bound in some special way. For example,
the .prevent modifier tells the v-on directive to call event.preventDefault() on the triggered event:

1 <form v-on:submit.prevent="onSubmit">...</form>

You'll see other examples of modifiers later, for v-on and for v-model , when we explore those features.

Shorthands
The v- prefix serves as a visual cue for identifying Vue-specific attributes in your templates. This is useful when you are using Vue.js
to apply dynamic behavior to some existing markup, but can feel verbose for some frequently used directives. At the same time, the
need for the v- prefix becomes less important when you are building a SPA , where Vue manages every template. Therefore, Vue
provides special shorthands for two of the most often used directives, v-bind and v-on :

v-bind Shorthand

1 <!-- full syntax -->


2 <a v-bind:href="url"> ... </a>
3
4 <!-- shorthand -->
5 <a :href="url"> ... </a>
6
7 <!-- shorthand with dynamic argument -->
8 <a :[key]="url"> ... </a>

v-on Shorthand
1 <!-- full syntax -->
2 <a v-on:click="doSomething"> ... </a>
3
4 <!-- shorthand -->
5 <a @click="doSomething"> ... </a>
6
7 <!-- shorthand with dynamic argument -->
8 <a @[event]="doSomething"> ... </a>

They may look a bit different from normal HTML, but : and @ are valid characters for attribute names and all Vue-supported
browsers can parse it correctly. In addition, they do not appear in the final rendered markup. The shorthand syntax is totally optional, but
you will likely appreciate it when you learn more about its usage later.

From the next page on, we'll use the shorthand in our examples, as that's the most common usage for Vue developers.

Caveats

Dynamic Argument Value Constraints

Dynamic arguments are expected to evaluate to a string, with the exception of null . The special value null can be used to explicitly
remove the binding. Any other non-string value will trigger a warning.

Dynamic Argument Expression Constraints

Dynamic argument expressions have some syntax constraints because certain characters, such as spaces and quotes, are invalid
inside HTML attribute names. For example, the following is invalid:

1 <!-- This will trigger a compiler warning. -->


2 <a v-bind:['foo' + bar]="value"> ... </a>
We recommend replacing any complex expressions with a computed property, one of the most fundamental pieces of Vue, which we'll
cover shortly.

When using in-DOM templates (templates directly written in an HTML file), you should also avoid naming keys with uppercase
characters, as browsers will coerce attribute names into lowercase:

1 <!--
2 This will be converted to v-bind:[someattr] in in-DOM templates.
3 Unless you have a "someattr" property in your instance, your code won't work.
4 -->
5 <a v-bind:[someAttr]="value"> ... </a>

JavaScript Expressions

Template expressions are sandboxed and only have access to a whitelist of globals such as Math and Date . You should not
attempt to access user defined globals in template expressions.
Data Properties and Methods

Data Properties
The data option for a component is a function. Vue calls this function as part of creating a new component instance. It should return
an object, which Vue will then wrap in its reactivity system and store on the component instance as $data . For convenience, any top-
level properties of that object are also exposed directly via the component instance:

1 const app = Vue.createApp({


2 data() {
3 return { count: 4 }
4 }
5 })
6
7 const vm = app.mount('#app')
8
9 console.log(vm.$data.count) // => 4
10 console.log(vm.count) // => 4
11
12 // Assigning a value to vm.count will also update $data.count
13 vm.count = 5
14 console.log(vm.$data.count) // => 5
15
16 // ... and vice-versa
17 vm.$data.count = 6
18 console.log(vm.count) // => 6
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 the component instance without including it in data . However, because this property isn't
backed by the reactive $data object, it won't automatically be tracked by Vue's reactivity system.

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.

Methods
To add methods to a component instance we use the methods option. This should be an object containing the desired methods:

1 const app = Vue.createApp({


2 data() {
3 return { count: 4 }
4 },
5 methods: {
6 increment() {
7 // `this` will refer to the component instance
8 this.count++
9 }
10 }
11 })
12
13 const vm = app.mount('#app')
14
15 console.log(vm.count) // => 4
16
17 vm.increment()
18
19 console.log(vm.count) // => 5

Vue automatically binds the this value for methods so that it always refers to the component instance. This ensures that a method
retains the correct this value if it's used as an event listener or callback. You should avoid using arrow functions when
defining methods , as that prevents Vue from binding the appropriate this value.

Just like all other properties of the component instance, the methods are accessible from within the component's template. Inside a
template they are most commonly used as event listeners:

1 <button @click="increment">Up vote</button>

In the example above, the method increment will be called when the <button> is clicked.

It is also possible to call a method directly from a template. As we'll see shortly, it's usually better to use a computed property instead.
However, using a method can be useful in scenarios where computed properties aren't a viable option. You can call a method anywhere
that a template supports JavaScript expressions:

1 <span :title="toTitleDate(date)">
2 {{ formatDate(date) }}
3 </span>

If the methods toTitleDate or formatDate access any reactive data then it will be tracked as a rendering dependency, just as if it had
been used in the template directly.

Methods called from a template should not have any side effects, such as changing data or triggering asynchronous processes. If you
find yourself tempted to do that you should probably use a lifecycle hook instead.
Debouncing and Throttling
Vue doesn't include built-in support for debouncing or throttling but it can be implemented using libraries such as Lodash .

In cases where a component is only used once, the debouncing can be applied directly within methods :

1 <script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
2 <script>
3 Vue.createApp({
4 methods: {
5 // Debouncing with Lodash
6 click: _.debounce(function() {
7 // ... respond to click ...
8 }, 500)
9 }
10 }).mount('#app')
11 </script>

However, this approach is potentially problematic for components that are reused because they'll all share the same debounced
function. To keep the component instances independent from each other, we can add the debounced function in the created lifecycle
hook:

app.component('save-button', {
created() {
// Debouncing with Lodash
this.debouncedClick = _.debounce(this.click, 500)
},
unmounted() {
// Cancel the timer when the component is removed
this.debouncedClick.cancel()
},
methods: {
click() {
// ... respond to click ...
}
},
template: `
<button @click="debouncedClick">
Save
</button>
`
})
Component Registration
This page assumes you've already read the Components Basics. Read that first if you are new to components.

Component Names
When registering a component, it will always be given a name. For example, in the global registration we've seen so far:

1 const app = Vue.createApp({...})


2
3 app.component('my-component-name', {
4 /* ... */
5 })

The component's name is the first argument of app.component . In the example above, the component's name is "my-component-
name".

The name you give a component may depend on where you intend to use it. When using a component directly in the DOM (as opposed
to in a string template or single-file component), we strongly recommend following the W3C rules for custom tag names:

1. All lowercase
2. Contains a hyphen (i.e., has multiple words connected with the hyphen symbol)

By doing so, this will help you avoid conflicts with current and future HTML elements.

You can see other recommendations for component names in the Style Guide.
Name Casing
When defining components in a string template or a single-file component, you have two options when defining component names:

With kebab-case

1 app.component('my-component-name', {
2 /* ... */
3 })

When defining a component with kebab-case, you must also use kebab-case when referencing its custom element, such as in <my-
component-name> .

With PascalCase

1 app.component('MyComponentName', {
2 /* ... */
3 })

When defining a component with PascalCase, you can use either case when referencing its custom element. That means both <my-
component-name> and <MyComponentName> are acceptable. Note, however, that only kebab-case names are valid directly in the DOM
(i.e. non-string templates).

Global Registration
So far, we've only created components using app.component :

1 Vue.createApp({...}).component('my-component-name', {
2 // ... options ...
3 })

These components are globally registered for the application. That means they can be used in the template of any component instance
within this application:

1 const app = Vue.createApp({})


2
3 app.component('component-a', {
4 /* ... */
5 })
6 app.component('component-b', {
7 /* ... */
8 })
9 app.component('component-c', {
10 /* ... */
11 })
12
13 app.mount('#app')

1 <div id="app">
2 <component-a></component-a>
3 <component-b></component-b>
4 <component-c></component-c>
5 </div>

This even applies to all subcomponents, meaning all three of these components will also be available inside each other.
Local Registration
Global registration often isn't ideal. For example, if you're using a build system like Webpack, globally registering all components means
that even if you stop using a component, it could still be included in your final build. This unnecessarily increases the amount of
JavaScript your users have to download.

In these cases, you can define your components as plain JavaScript objects:

1 const ComponentA = {
2 /* ... */
3 }
4 const ComponentB = {
5 /* ... */
6 }
7 const ComponentC = {
8 /* ... */
9 }

Then define the components you'd like to use in a components option:

1 const app = Vue.createApp({


2 components: {
3 'component-a': ComponentA,
4 'component-b': ComponentB
5 }
6 })
For each property in the components object, the key will be the name of the custom element, while the value will contain the options
object for the component.

Note that locally registered components are not also available in subcomponents. For example, if you wanted ComponentA to be
available in ComponentB , you'd have to use:

1 const ComponentA = {
2 /* ... */
3 }
4
5 const ComponentB = {
6 components: {
7 'component-a': ComponentA
8 }
9 // ...
10 }

Or if you're using ES2015 modules, such as through Babel and Webpack, that might look more like:

1 import ComponentA from './ComponentA.vue'


2
3 export default {
4 components: {
5 ComponentA
6 }
7 // ...
8 }

Note that in ES2015+, placing a variable name like ComponentA inside an object is shorthand for ComponentA: ComponentA , meaning
the name of the variable is both:

the custom element name to use in the template, and


the name of the variable containing the component options

Module Systems
If you're not using a module system with import / require , you can probably skip this section for now. If you are, we have some
special instructions and tips just for you.

Local Registration in a Module System


If you're still here, then it's likely you're using a module system, such as with Babel and Webpack. In these cases, we recommend
creating a components directory, with each component in its own file.

Then you'll need to import each component you'd like to use, before you locally register it. For example, in a
hypothetical ComponentB.js or ComponentB.vue file:

1 import ComponentA from './ComponentA'


2 import ComponentC from './ComponentC'
3
4 export default {
5 components: {
6 ComponentA,
7 ComponentC
8 }
9 // ...
10 }

Now both ComponentA and ComponentC can be used inside ComponentB 's template.
Props
This page assumes you've already read the Components Basics. Read that first if you are new to components.

Prop Types
So far, we've only seen props listed as an array of strings:

1 props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

Usually though, you'll want every prop to be a specific type of value. In these cases, you can list props as an object, where the
properties' names and values contain the prop names and types, respectively:

1 props: {
2 title: String,
3 likes: Number,
4 isPublished: Boolean,
5 commentIds: Array,
6 author: Object,
7 callback: Function,
8 contactsPromise: Promise // or any other constructor
9 }

This not only documents your component, but will also warn users in the browser's JavaScript console if they pass the wrong type. You'll
learn much more about type checks and other prop validations further down this page.
Passing Static or Dynamic Props
So far, you've seen props passed a static value, like in:

1 <blog-post title="My journey with Vue"></blog-post>

You've also seen props assigned dynamically with v-bind or its shortcut, the : character, such as in:

1 <!-- Dynamically assign the value of a variable -->


2 <blog-post :title="post.title"></blog-post>
3
4 <!-- Dynamically assign the value of a complex expression -->
5 <blog-post :title="post.title + ' by ' + post.author.name"></blog-post>

In the two examples above, we happen to pass string values, but any type of value can actually be passed to a prop.

Passing a Number

1 <!-- Even though `42` is static, we need v-bind to tell Vue that -->
2 <!-- this is a JavaScript expression rather than a string. -->
3 <blog-post :likes="42"></blog-post>
4
5 <!-- Dynamically assign to the value of a variable. -->
6 <blog-post :likes="post.likes"></blog-post>
Passing a Boolean

1 <!-- Including the prop with no value will imply `true`. -->
2 <blog-post is-published></blog-post>
3
4 <!-- Even though `false` is static, we need v-bind to tell Vue that -->
5 <!-- this is a JavaScript expression rather than a string. -->
6 <blog-post :is-published="false"></blog-post>
7
8 <!-- Dynamically assign to the value of a variable. -->
9 <blog-post :is-published="post.isPublished"></blog-post>

Passing an Array

1 <!-- Even though the array is static, we need v-bind to tell Vue that -->
2 <!-- this is a JavaScript expression rather than a string. -->
3 <blog-post :comment-ids="[234, 266, 273]"></blog-post>
4
5 <!-- Dynamically assign to the value of a variable. -->
6 <blog-post :comment-ids="post.commentIds"></blog-post>

Passing an Object

1 <!-- Even though the object is static, we need v-bind to tell Vue that -->
2 <!-- this is a JavaScript expression rather than a string. -->
3 <blog-post
4 :author="{
5 name: 'Veronica',
6 company: 'Veridian Dynamics'
7 }"
8 ></blog-post>
9
10 <!-- Dynamically assign to the value of a variable. -->
11 <blog-post :author="post.author"></blog-post>

Passing the Properties of an Object


If you want to pass all the properties of an object as props, you can use v-bind without an argument ( v-bind instead of :prop-
name ). For example, given a post object:

1 post: {
2 id: 1,
3 title: 'My Journey with Vue'
4 }

The following template:

1 <blog-post v-bind="post"></blog-post>

Will be equivalent to:

1 <blog-post v-bind:id="post.id" v-bind:title="post.title"></blog-post>


One-Way Data Flow
All props form a one-way-down binding between the child property and the parent one: when the parent property updates, it will flow
down to the child, but not the other way around. This prevents child components from accidentally mutating the parent's state, which can
make your app's data flow harder to understand.

In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This
means you should not attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console.

There are usually two cases where it's tempting to mutate a prop:

1. The prop is used to pass in an initial value; the child component wants to use it as a local data property afterwards. In this case, it's
best to define a local data property that uses the prop as its initial value:

1 props: ['initialCounter'],
2 data() {
3 return {
4 counter: this.initialCounter
5 }
6 }

2. The prop is passed in as a raw value that needs to be transformed. In this case, it's best to define a computed property using the
prop's value:

1 props: ['size'],
2 computed: {
3 normalizedSize: function () {
4 return this.size.trim().toLowerCase()
5 }
6 }

Note

Note that objects and arrays in JavaScript are passed by reference, so if the prop is an array or object, mutating the object or
array itself inside the child component will affect parent state.

Prop Validation
Components can specify requirements for their props, such as the types you've already seen. If a requirement isn't met, Vue will warn
you in the browser's JavaScript console. This is especially useful when developing a component that's intended to be used by others.

To specify prop validations, you can provide an object with validation requirements to the value of props , instead of an array of strings.
For example:

1 app.component('my-component', {
2 props: {
3 // Basic type check (`null` and `undefined` values will pass any type validation)
4 propA: Number,
5 // Multiple possible types
6 propB: [String, Number],
7 // Required string
8 propC: {
9 type: String,
10 required: true
11 },
12 // Number with a default value
13 propD: {
14 type: Number,
15 default: 100
16 },
17 // Object with a default value
18 propE: {
19 type: Object,
20 // Object or array defaults must be returned from
21 // a factory function
22 default: function() {
23 return { message: 'hello' }
24 }
25 },
26 // Custom validator function
27 propF: {
28 validator: function(value) {
29 // The value must match one of these strings
30 return ['success', 'warning', 'danger'].indexOf(value) !== -1
31 }
32 },
33 // Function with a default value
34 propG: {
35 type: Function,
36 // Unlike object or array default, this is not a factory function - this is a function to serve as a default value
37 default: function() {
38 return 'Default function'
39 }
40 }
41 }
42 })

When prop validation fails, Vue will produce a console warning (if using the development build).

Note
Note that props are validated before a component instance is created, so instance properties (e.g. data , computed , etc) will
not be available inside default or validator functions.

Type Checks
The type can be one of the following native constructors:

String
Number
Boolean
Array
Object
Date
Function
Symbol

In addition, type can also be a custom constructor function and the assertion will be made with an instanceof check. For example,
given the following constructor function exists:

1 function Person(firstName, lastName) {


2 this.firstName = firstName
3 this.lastName = lastName
4 }

You could use:

1 app.component('blog-post', {
2 props: {
3 author: Person
4 }
5 })

to validate that the value of the author prop was created with new Person .

Prop Casing (camelCase vs kebab-case)


HTML attribute names are case-insensitive, so browsers will interpret any uppercase characters as lowercase. That means when you're
using in-DOM templates, camelCased prop names need to use their kebab-cased (hyphen-delimited) equivalents:

1 const app = Vue.createApp({})


2
3 app.component('blog-post', {
4 // camelCase in JavaScript
5 props: ['postTitle'],
6 template: '<h3>{{ postTitle }}</h3>'
7 })

1 <!-- kebab-case in HTML -->


2 <blog-post post-title="hello!"></blog-post>

Again, if you're using string templates, this limitation does not apply.
Non-Prop Attributes
This page assumes you've already read the Components Basics. Read that first if you are new to components.

A component non-prop attribute is an attribute or event listener that is passed to a component, but does not have a corresponding
property defined in props or emits. Common examples of this include class , style , and id attributes. You can access those
attributes via $attrs property.

Attribute Inheritance
When a component returns a single root node, non-prop attributes will automatically be added to the root node's attributes. For example,
in the instance of a date-picker component:

1 app.component('date-picker', {
2 template: `
3 <div class="date-picker">
4 <input type="datetime" />
5 </div>
6 `
7 })

In the event we need to define the status of the date-picker component via a data-status property, it will be applied to the root node
(i.e., div.date-picker ).
1 <!-- Date-picker component with a non-prop attribute -->
2 <date-picker data-status="activated"></date-picker>
3
4 <!-- Rendered date-picker component -->
5 <div class="date-picker" data-status="activated">
6 <input type="datetime" />
7 </div>

Same rule applies to the event listeners:

1 <date-picker @change="submitChange"></date-picker>

1 app.component('date-picker', {
2 created() {
3 console.log(this.$attrs) // { onChange: () => {} }
4 }
5 })

This might be helpful when we have an HTML element with change event as a root element of date-picker .

1 app.component('date-picker', {
2 template: `
3 <select>
4 <option value="1">Yesterday</option>
5 <option value="2">Today</option>
6 <option value="3">Tomorrow</option>
7 </select>
8 `
9 })
In this case, change event listener is passed from the parent component to the child and it will be triggered on
native <select> change event. We won't need to emit an event from the date-picker explicitly:

1 <div id="date-picker" class="demo">


2 <date-picker @change="showChange"></date-picker>
3 </div>

1 const app = Vue.createApp({


2 methods: {
3 showChange(event) {
4 console.log(event.target.value) // will log a value of the selected option
5 }
6 }
7 })

Disabling Attribute Inheritance


If you do not want a component to automatically inherit attributes, you can set inheritAttrs: false in the component's options.

The common scenario for disabling an attribute inheritance is when attributes need to be applied to other elements besides the root
node.

By setting the inheritAttrs option to false , you can control to apply to other elements attributes to use the
component's $attrs property, which includes all attributes not included to component props and emits properties
(e.g., class , style , v-on listeners, etc.).

Using our date-picker component example from the previous section, in the event we need to apply all non-prop attributes to
the input element rather than the root div element, this can be accomplished by using the v-bind shortcut.
1 app.component('date-picker', {
2 inheritAttrs: false,
3 template: `
4 <div class="date-picker">
5 <input type="datetime" v-bind="$attrs" />
6 </div>
7 `
8 })

With this new configuration, our data-status attribute will be applied to our input element!

1 <!-- Date-picker component with a non-prop attribute -->


2 <date-picker data-status="activated"></date-picker>
3
4 <!-- Rendered date-picker component -->
5 <div class="date-picker">
6 <input type="datetime" data-status="activated" />
7 </div>

Attribute Inheritance on Multiple Root Nodes


Unlike single root node components, components with multiple root nodes do not have an automatic attribute fallthrough behavior.
If $attrs are not bound explicitly, a runtime warning will be issued.

1 <custom-layout id="custom-layout" @click="changeValue"></custom-layout>

// This will raise a warning


app.component('custom-layout', {
template: `
<header>...</header>
<main>...</main>
<footer>...</footer>
`
})

// No warnings, $attrs are passed to <main> element


app.component('custom-layout', {
template: `
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
`
})
Custom Events
This page assumes you've already read the Components Basics. Read that first if you are new to
components.

Event Names
Like components and props, event names provide an automatic case transformation. If you emit an
event from the child component in camel case, you will be able to add a kebab-cased listener in the
parent:

1 this.$emit('myEvent')

1 <my-component @my-event="doSomething"></my-component>

As with props casing, we recommend using kebab-cased event listeners when you are using in-DOM
templates. If you're using string templates, this limitation does not apply.

Defining Custom Events


Watch a free video on how to define custom events on Vue School

Emitted events can be defined on the component via the emits option.

1 app.component('custom-form', {
2 emits: ['inFocus', 'submit']
3 })

When a native event (e.g., click ) is defined in the emits option, the component event will be
used instead of a native event listener.

TIP

It is recommended to define all emitted events in order to better document how a component
should work.

Validate Emitted Events


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 $emit call and returns a boolean to indicate whether the event is valid or not.

1 app.component('custom-form', {
2 emits: {
3 // No validation
4 click: null,
5
6 // Validate submit event
7 submit: ({ email, password }) => {
8 if (email && password) {
9 return true
10 } else {
11 console.warn('Invalid submit event payload!')
12 return false
13 }
14 }
15 },
16 methods: {
17 submitForm() {
18 this.$emit('submit', { email, password })
19 }
20 }
21 })

v-model arguments

By default, v-model on a component uses modelValue as the prop and update:modelValue as the
event. We can modify these names passing an argument to v-model :

1 <my-component v-model:title="bookTitle"></my-component>

In this case, child component will expect a title prop and emits update:title event to sync:

1 app.component('my-component', {
2 props: {
3 title: String
4 },
5 emits: ['update:title'],
6 template: `
7 <input
8 type="text"
9 :value="title"
10 @input="$emit('update:title', $event.target.value)">
11 `
12 })

1 <my-component v-model:title="bookTitle"></my-component>

Multiple v-model bindings


By leveraging the ability to target a particular prop and event as we learned before with v-
model arguments, we can now create multiple v-model bindings on a single component instance.

Each v-model will sync to a different prop, without the need for extra options in the component:

1 <user-name
2 v-model:first-name="firstName"
3 v-model:last-name="lastName"
4 ></user-name>

1 app.component('user-name', {
2 props: {
3 firstName: String,
4 lastName: String
5 },
6 emits: ['update:firstName', 'update:lastName'],
7 template: `
8 <input
9 type="text"
10 :value="firstName"
11 @input="$emit('update:firstName', $event.target.value)">
12
13 <input
14 type="text"
15 :value="lastName"
16 @input="$emit('update:lastName', $event.target.value)">
17 `
18 })

Handling v-model modifiers


When we were learning about form input bindings, we saw that v-model has built-in
modifiers - .trim , .number and .lazy . In some cases, however, you might also want to add your
own custom modifiers.

Let's create an example custom modifier, capitalize , that capitalizes the first letter of the string
provided by the v-model binding.

Modifiers added to a component v-model will be provided to the component via


the modelModifiers prop. In the below example, we have created a component that contains
a modelModifiers prop that defaults to an empty object.

Notice that when the component's created lifecycle hook triggers, the modelModifiers prop
contains capitalize and its value is true - due to it being set on the v-model binding v-
model.capitalize="myText" .
1 <my-component v-model.capitalize="myText"></my-component>

1 app.component('my-component', {
2 props: {
3 modelValue: String,
4 modelModifiers: {
5 default: () => ({})
6 }
7 },
8 emits: ['update:modelValue'],
9 template: `
10 <input type="text"
11 :value="modelValue"
12 @input="$emit('update:modelValue', $event.target.value)">
13 `,
14 created() {
15 console.log(this.modelModifiers) // { capitalize: true }
16 }
17 })

Now that we have our prop set up, we can check the modelModifiers object keys and write a handler to
change the emitted value. In the code below we will capitalize the string whenever the <input
/> element fires an input event.

1 <div id="app">
2 <my-component v-model.capitalize="myText"></my-component>
3 {{ myText }}
4 </div>

1 const app = Vue.createApp({


2 data() {
3 return {
4 myText: ''
5 }
6 }
7 })
8
9 app.component('my-component', {
10 props: {
11 modelValue: String,
12 modelModifiers: {
13 default: () => ({})
14 }
15 },
16 emits: ['update:modelValue'],
17 methods: {
18 emitValue(e) {
19 let value = e.target.value
20 if (this.modelModifiers.capitalize) {
21 value = value.charAt(0).toUpperCase() + value.slice(1)
22 }
23 this.$emit('update:modelValue', value)
24 }
25 },
26 template: `<input
27 type="text"
28 :value="modelValue"
29 @input="emitValue">`
30 })
31
32 app.mount('#app')

For v-model bindings with arguments, the generated prop name will be arg + "Modifiers" :

1 <my-component v-model:description.capitalize="myText"></my-component>
1 app.component('my-component', {
2 props: ['description', 'descriptionModifiers'],
3 emits: ['update:description'],
4 template: `
5 <input type="text"
6 :value="description"
7 @input="$emit('update:description', $event.target.value)">
8 `,
9 created() {
10 console.log(this.descriptionModifiers) // { capitalize: true }
11 }
12 })
Slots
This page assumes you've already read the Components Basics. Read that first if you are new to components.

Slot Content
Vue implements a content distribution API inspired by the Web Components spec draft , using the <slot> element to serve as
distribution outlets for content.

This allows you to compose components like this:

1 <todo-button>
2 Add todo
3 </todo-button>

Then in the template for <todo-button> , you might have:

1 <!-- todo-button component template -->


2 <button class="btn-primary">
3 <slot></slot>
4 </button>

When the component renders, <slot></slot> will be replaced by "Add Todo".


1 <!-- rendered HTML -->
2 <button class="btn-primary">
3 Add todo
4 </button>

Strings are just the beginning though! Slots can also contain any template code, including HTML:

1 <todo-button>
2 <!-- Add a Font Awesome icon -->
3 <i class="fas fa-plus"></i>
4 Add todo
5 </todo-button>

Or even other components:

1 <todo-button>
2 <!-- Use a component to add an icon -->
3 <font-awesome-icon name="plus"></font-awesome-icon>
4 Add todo
5 </todo-button>

If <todo-button> 's template did not contain a <slot> element, any content provided between its opening and closing tag would be
discarded.

1 <!-- todo-button component template -->


2
3 <button class="btn-primary">
4 Create a new item
5 </button>
1 <todo-button>
2 <!-- Following text won't be rendered -->
3 Add todo
4 </todo-button>

Render Scope
When you want to use data inside a slot, such as in:

1 <todo-button>
2 Delete a {{ item.name }}
3 </todo-button>

That slot has access to the same instance properties (i.e. the same "scope") as the rest of the template.
The slot does not have access to <todo-button> 's scope. For example, trying to access action would not work:

1 <todo-button action="delete">
2 Clicking here will {{ action }} an item
3 <!--
4 The `action` will be undefined, because this content is passed
5 _to_ <todo-button>, rather than defined _inside_ the
6 <todo-button> component.
7 -->
8 </todo-button>
As a rule, remember that:

Everything in the parent template is compiled in parent scope; everything in the child template is compiled in the child scope.

Fallback Content
There are cases when it's useful to specify fallback (i.e. default) content for a slot, to be rendered only when no content is provided. For
example, in a <submit-button> component:

1 <button type="submit">
2 <slot></slot>
3 </button>

We might want the text "Submit" to be rendered inside the <button> most of the time. To make "Submit" the fallback content, we can
place it in between the <slot> tags:

1 <button type="submit">
2 <slot>Submit</slot>
3 </button>

Now when we use <submit-button> in a parent component, providing no content for the slot:

1 <submit-button></submit-button>

will render the fallback content, "Submit":


1 <button type="submit">
2 Submit
3 </button>

But if we provide content:

1 <submit-button>
2 Save
3 </submit-button>

Then the provided content will be rendered instead:

1 <button type="submit">
2 Save
3 </button>

Named Slots
There are times when it's useful to have multiple slots. For example, in a <base-layout> component with the following template:

1 <div class="container">
2 <header>
3 <!-- We want header content here -->
4 </header>
5 <main>
6 <!-- We want main content here -->
7 </main>
8 <footer>
9 <!-- We want footer content here -->
10 </footer>
11 </div>

For these cases, the <slot> element has a special attribute, name , which can be used to assign a unique ID to different slots so you
can determine where content should be rendered:

1 <div class="container">
2 <header>
3 <slot name="header"></slot>
4 </header>
5 <main>
6 <slot></slot>
7 </main>
8 <footer>
9 <slot name="footer"></slot>
10 </footer>
11 </div>

A <slot> outlet without name implicitly has the name "default".

To provide content to named slots, we need to use the v-slot directive on a <template> element, providing the name of the slot
as v-slot 's argument:

1 <base-layout>
2 <template v-slot:header>
3 <h1>Here might be a page title</h1>
4 </template>
5
6 <template v-slot:default>
7 <p>A paragraph for the main content.</p>
8 <p>And another one.</p>
9 </template>
10
11 <template v-slot:footer>
12 <p>Here's some contact info</p>
13 </template>
14 </base-layout>

Now everything inside the <template> elements will be passed to the corresponding slots.

The rendered HTML will be:

1 <div class="container">
2 <header>
3 <h1>Here might be a page title</h1>
4 </header>
5 <main>
6 <p>A paragraph for the main content.</p>
7 <p>And another one.</p>
8 </main>
9 <footer>
10 <p>Here's some contact info</p>
11 </footer>
12 </div>

Note that v-slot can only be added to a <template> (with one exception)

Scoped Slots
Sometimes, it's useful for slot content to have access to data only available in the child component. It's a common case when a
component is used to render an array of items, and we want to be able to customize the way each item is rendered.

For example, we have a component, containing a list of todo-items.


1 app.component('todo-list', {
2 data() {
3 return {
4 items: ['Feed a cat', 'Buy milk']
5 }
6 },
7 template: `
8 <ul>
9 <li v-for="(item, index) in items">
10 {{ item }}
11 </li>
12 </ul>
13 `
14 })

We might want to replace the {{ item }} with a <slot> to customize it on parent component:

1 <todo-list>
2 <i class="fas fa-check"></i>
3 <span class="green">{{ item }}</span>
4 </todo-list>

That won't work, however, because only the <todo-list> component has access to the item and we are providing the slot content
from its parent.

To make item available to the slot content provided by the parent, we can add a <slot> element and bind it as an attribute:

1 <ul>
2 <li v-for="( item, index ) in items">
3 <slot :item="item"></slot>
4 </li>
5 </ul>
You can bind as many attributes to the slot as you need:

1 <ul>
2 <li v-for="( item, index ) in items">
3 <slot :item="item" :index="index" :another-attribute="anotherAttribute"></slot>
4 </li>
5 </ul>

Attributes bound to a <slot> element are called slot props. Now, in the parent scope, we can use v-slot with a value to define a
name for the slot props we've been provided:

1 <todo-list>
2 <template v-slot:default="slotProps">
3 <i class="fas fa-check"></i>
4 <span class="green">{{ slotProps.item }}</span>
5 </template>
6 </todo-list>
In this example, we've chosen to name the object containing all our slot props slotProps , but you can use any name you like.

Abbreviated Syntax for Lone Default Slots


In cases like above, when only the default slot is provided content, the component's tags can be used as the slot's template. This allows
us to use v-slot directly on the component:

1 <todo-list v-slot:default="slotProps">
2 <i class="fas fa-check"></i>
3 <span class="green">{{ slotProps.item }}</span>
4 </todo-list>

This can be shortened even further. Just as non-specified content is assumed to be for the default slot, v-slot without an argument is
assumed to refer to the default slot:

1 <todo-list v-slot="slotProps">
2 <i class="fas fa-check"></i>
3 <span class="green">{{ slotProps.item }}</span>
4 </todo-list>

Note that the abbreviated syntax for default slot cannot be mixed with named slots, as it would lead to scope ambiguity:

1 <!-- INVALID, will result in warning -->


2 <todo-list v-slot="slotProps">
3 <i class="fas fa-check"></i>
4 <span class="green">{{ slotProps.item }}</span>
5
6 <template v-slot:other="otherSlotProps">
7 slotProps is NOT available here
8 </template>
9 </todo-list>

Whenever there are multiple slots, use the full <template> based syntax for all slots:
1 <todo-list>
2 <template v-slot:default="slotProps">
3 <i class="fas fa-check"></i>
4 <span class="green">{{ slotProps.item }}</span>
5 </template>
6
7 <template v-slot:other="otherSlotProps">
8 ...
9 </template>
10 </todo-list>

Destructuring Slot Props


Internally, scoped slots work by wrapping your slot content in a function passed a single argument:

1 function (slotProps) {
2 // ... slot content ...
3 }

That means the value of v-slot can actually accept any valid JavaScript expression that can appear in the argument position of a
function definition. So you can also use ES2015 destructuring to pull out specific slot props, like so:

1 <todo-list v-slot="{ item }">


2 <i class="fas fa-check"></i>
3 <span class="green">{{ item }}</span>
4 </todo-list>

This can make the template much cleaner, especially when the slot provides many props. It also opens other possibilities, such as
renaming props, e.g. item to todo :
1 <todo-list v-slot="{ item: todo }">
2 <i class="fas fa-check"></i>
3 <span class="green">{{ todo }}</span>
4 </todo-list>

You can even define fallbacks, to be used in case a slot prop is undefined:

1 <todo-list v-slot="{ item = 'Placeholder' }">


2 <i class="fas fa-check"></i>
3 <span class="green">{{ item }}</span>
4 </todo-list>

Dynamic Slot Names


Dynamic directive arguments also work on v-slot , allowing the definition of dynamic slot names:

1 <base-layout>
2 <template v-slot:[dynamicSlotName]>
3 ...
4 </template>
5 </base-layout>

Named Slots Shorthand


Similar to v-on and v-bind , v-slot also has a shorthand, replacing everything before the argument ( v-slot: ) with the special
symbol # . For example, v-slot:header can be rewritten as #header :
1 <base-layout>
2 <template #header>
3 <h1>Here might be a page title</h1>
4 </template>
5
6 <template #default>
7 <p>A paragraph for the main content.</p>
8 <p>And another one.</p>
9 </template>
10
11 <template #footer>
12 <p>Here's some contact info</p>
13 </template>
14 </base-layout>

However, just as with other directives, the shorthand is only available when an argument is provided. That means the following syntax is
invalid:

1 <!-- This will trigger a warning -->


2
3 <todo-list #="{ item }">
4 <i class="fas fa-check"></i>
5 <span class="green">{{ item }}</span>
6 </todo-list>

Instead, you must always specify the name of the slot if you wish to use the shorthand:

<todo-list #default="{ item }">


<i class="fas fa-check"></i>
<span class="green">{{ item }}</span>
</todo-list>
Dynamic & Async Components
This page assumes you've already read the Components Basics. Read that first if you are new to components.

Dynamic Components with keep-alive


Earlier, we used the is attribute to switch between components in a tabbed interface:

1 <component :is="currentTabComponent"></component>

When switching between these components though, you'll sometimes want to maintain their state or avoid re-rendering for performance
reasons. For example, when expanding our tabbed interface a little:

You'll notice that if you select a post, switch to the Archive tab, then switch back to Posts, it's no longer showing the post you selected.
That's because each time you switch to a new tab, Vue creates a new instance of the currentTabComponent .

Recreating dynamic components is normally useful behavior, but in this case, we'd really like those tab component instances to be
cached once they're created for the first time. To solve this problem, we can wrap our dynamic component with a <keep-
alive> element:

1 <!-- Inactive components will be cached! -->


2 <keep-alive>
3 <component :is="currentTabComponent"></component>
4 </keep-alive>
Check out the result below:

Now the Posts tab maintains its state (the selected post) even when it's not rendered.

Check out more details on <keep-alive> in the API reference.

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 possible, Vue has a defineAsyncComponent method:

1 const app = Vue.createApp({})


2
3 const AsyncComp = Vue.defineAsyncComponent(
4 () =>
5 new Promise((resolve, reject) => {
6 resolve({
7 template: '<div>I am async!</div>'
8 })
9 })
10 )
11
12 app.component('async-example', AsyncComp)

As you can see, this method accepts a factory function returning a Promise . Promise's resolve callback should be called when you
have retrieved your component definition from the server. You can also call reject(reason) to indicate the load has failed.

You can also return a Promise in the factory function, so with Webpack 2 or later and ES2015 syntax you can do:

1 import { defineAsyncComponent } from 'vue'


2
3 const AsyncComp = defineAsyncComponent(() =>
4 import('./components/AsyncComponent.vue')
5 )
6
7 app.component('async-component', AsyncComp)

You can also use defineAsyncComponent when registering a component locally:

1 import { createApp, defineAsyncComponent } from 'vue'


2
3 createApp({
4 // ...
5 components: {
6 AsyncComponent: defineAsyncComponent(() =>
7 import('./components/AsyncComponent.vue')
8 )
9 }
10 })

Using with Suspense


Async components are suspensible by default. This means if it has a <Suspense> in the parent chain, it will be treated as an async
dependency of that <Suspense> . In this case, the loading state will be controlled by the <Suspense> , and the component's own
loading, error, delay and timeout options will be ignored.

The async component can opt-out of Suspense control and let the component always control its own loading state by
specifying suspensible: false in its options.

You can check the list of available options in the API Reference
Handling Edge Cases
This page assumes you've already read the Components Basics. Read that first if you are new to components.

Note

All the features on this page document the handling of edge cases, meaning unusual situations that sometimes require bending
Vue's rules a little. Note however, that they all have disadvantages or situations where they could be dangerous. These are
noted in each case, so keep them in mind when deciding to use each feature.

Controlling Updates
Thanks to Vue's Reactivity system, it always knows when to update (if you use it correctly). There are edge cases, however, when you
might want to force an update, despite the fact that no reactive data has changed. Then there are other cases when you might want to
prevent unnecessary updates.

Forcing an Update
If you find yourself needing to force an update in Vue, in 99.99% of cases, you've made a mistake somewhere. For example, you may
be relying on state that isn't tracked by Vue's reactivity system, e.g. with data property added after component creation.

However, if you've ruled out the above and find yourself in this extremely rare situation of having to manually force an update, you can
do so with $forceUpdate .
Cheap Static Components with v-once
Rendering plain HTML elements is very fast in Vue, but sometimes you might have a component that contains a lot of static content. In
these cases, you can ensure that it's only evaluated once and then cached by adding the v-once directive to the root element, like this:

1 app.component('terms-of-service', {
2 template: `
3 <div v-once>
4 <h1>Terms of Service</h1>
5 ... a lot of static content ...
6 </div>
7 `
8 })

TIP

Once again, try not to overuse this pattern. While convenient in those rare cases when you have to render a lot of static content,
it's simply not necessary unless you actually notice slow rendering - plus, it could cause a lot of confusion later. For example,
imagine another developer who's not familiar with v-once or simply misses it in the template. They might spend hours trying to
figure out why the template isn't updating correctly.
Overview
Vue offers some abstractions that can help work with transitions and animations, particularly in response to something changing. Some
of these abstractions include:

Hooks for components entering and leaving the DOM, in both CSS and JS, using the built-in <transition> component.
Transition Modes so that you can orchestrate ordering during a transition.
Hooks for when multiple elements are updating in position, with FLIP techniques applied under the hood to increase performance,
using the <transition-group> component.
Transitioning different states in an application, with watchers .

We will cover all of these and more in the next three sections in this Guide. However, aside from these useful API offerings, it's worth
mentioning that the class and style declarations we covered earlier can be used to apply animations and transitions as well, for more
simple use cases.

In this next section, we'll go over some web animation and transitions basics, and link off to some resources for further exploration. If
you're already familiar with web animation and how those principles might work with some of Vue's directives, feel free to skip this next
section. For anyone else looking to learn a little more about web animation basics before diving in, read on.

Class-based Animations & Transitions


Though the <transition> component can be wonderful for components entering and leaving, you can also activate an animation
without mounting a component, by adding a conditional class.
1 <div id="demo">
2 Push this button to do something you shouldn't be doing:<br />
3
4 <div :class="{ shake: noActivated }">
5 <button @click="noActivated = true">Click me</button>
6 <span v-if="noActivated">Oh no!</span>
7 </div>
8 </div>

1 .shake {
2 animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
3 transform: translate3d(0, 0, 0);
4 backface-visibility: hidden;
5 perspective: 1000px;
6 }
7
8 @keyframes shake {
9 10%,
10 90% {
11 transform: translate3d(-1px, 0, 0);
12 }
13
14 20%,
15 80% {
16 transform: translate3d(2px, 0, 0);
17 }
18
19 30%,
20 50%,
21 70% {
22 transform: translate3d(-4px, 0, 0);
23 }
24
25 40%,
26 60% {
27 transform: translate3d(4px, 0, 0);
28 }
29 }

1 const Demo = {
2 data() {
3 return {
4 noActivated: false
5 }
6 }
7 }
8
9 Vue.createApp(Demo).mount('#demo')

Transitions with Style Bindings


Some transition effects can be applied by interpolating values, for instance by binding a style to an element while an interaction occurs.
Take this example for instance:

1 <div id="demo">
2 <div
3 @mousemove="xCoordinate"
4 :style="{ backgroundColor: `hsl(${x}, 80%, 50%)` }"
5 class="movearea"
6 >
7 <h3>Move your mouse across the screen...</h3>
8 <p>x: {{x}}</p>
9 </div>
10 </div>
1 .movearea {
2 transition: 0.2s background-color ease;
3 }

1 const Demo = {
2 data() {
3 return {
4 x: 0
5 }
6 },
7 methods: {
8 xCoordinate(e) {
9 this.x = e.clientX
10 }
11 }
12 }
13
14 Vue.createApp(Demo).mount('#demo')

In this example, we are creating animation through the use of interpolation, attached to the mouse movement. The CSS transition is
applied to the element as well, to let the element know what kind of easing to use while it's updating.

Performance
You may notice that the animations shown above are using things like transforms , and applying strange properties like perspective -
why were they built that way instead of just using margin and top etc?

We can create extremely smooth animations on the web by being aware of performance. We want to hardware accelerate elements
when we can, and use properties that don't trigger repaints. Let's go over some of how we can accomplish this.
Transform and Opacity
We can check resources like CSS-Triggers to see which properties will trigger repaints if we animate them. Here, if you look
under transform , you will see:

Changing transform does not trigger any geometry changes or painting, which is very good. This means that the operation can likely
be carried out by the compositor thread with the help of the GPU.

Opacity behaves similarly. Thus, they are ideal candidates for movement on the web.

Hardware Acceleration
Properties such as perspective , backface-visibility , and transform: translateZ(x) will allow the browser to know you need
hardware acceleration.

If you wish to hardware-accelerate an element, you can apply any of these properties (not all are necessary, only one):

1 perspective: 1000px;
2 backface-visibility: hidden;
3 transform: translateZ(0);

Many JS libraries like GreenSock will assume you want hardware acceleration and will apply them by default, so you do not need to set
them manually.
Timing
For simple UI transitions, meaning from just one state to another with no intermediary states, it's common to use timings between 0.1s
and 0.4s, and most folks find that 0.25s tends to be a sweet spot. Can you use that timing for everything? No, not really. If you have
something that needs to move a greater distance or has more steps or state changes, 0.25s is not going to work as well and you will
have to be much more intentional, and the timing will need to be more unique. That doesn't mean you can't have nice defaults that you
repeat within your application, though.

You may also find that entrances look better with slightly more time than an exit. The user typically is being guided during the entrance,
and is a little less patient upon exit because they want to go on their way.

Easing
Easing is an important way to convey depth in an animation. One of the most common mistakes newcomers to animation make is to
use ease-in for entrances, and ease-out for exits. You'll actually need the opposite.

If we were to apply these states to a transition, it would look something like this:

1 .button {
2 background: #1b8f5a;
3 /* applied to the initial state, so this transition will be applied to the return state */
4 transition: background 0.25s ease-in;
5 }
6
7 .button:hover {
8 background: #3eaf7c;
9 /* applied to the hover state, so this transition will be applied when a hover is triggered */
10 transition: background 0.35s ease-out;
11 }

Easing can also convey the quality of material being animated. Take this pen for example, which ball do you think is hard and which is
soft?

You can get a lot of unique effects and make your animation very stylish by adjusting your easing. CSS allows you to modify this by
adjusting a cubic bezier property, this playground by Lea Verou is very helpful for exploring this.

Though you can achieve great effects for simple animation with the two handles the cubic-bezier ease offers, JavaScript allows multiple
handles, and therefore, allows for much more variance.
Value

Value
Progress Progress

CSS - limited handles JS - multiple handles


Take a bounce, for instance. In CSS we have to declare each keyframe, up and down. In JavaScript, we can express all of that
movement within the ease, by declaring bounce in the GreenSock API (GSAP) (other JS libraries have other types of easing
defaults).

Here is the code used for a bounce in CSS (example from animate.css):
1 @keyframes bounceInDown {
2 from,
3 60%,
4 75%,
5 90%,
6 to {
7 animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
8 }
9
10 0% {
11 opacity: 0;
12 transform: translate3d(0, -3000px, 0) scaleY(3);
13 }
14
15 60% {
16 opacity: 1;
17 transform: translate3d(0, 25px, 0) scaleY(0.9);
18 }
19
20 75% {
21 transform: translate3d(0, -10px, 0) scaleY(0.95);
22 }
23
24 90% {
25 transform: translate3d(0, 5px, 0) scaleY(0.985);
26 }
27
28 to {
29 transform: translate3d(0, 0, 0);
30 }
31 }
32
33 .bounceInDown {
34 animation-name: bounceInDown;
35 }
And here is the same bounce in JS using GreenSock:

1 gsap.from(element, { duration: 1, ease: 'bounce.out', y: -500 })

We'll be using GreenSock in some of the examples in the sections following. They have a great ease visualizer that will help you build
nicely crafted eases.

# Further Reading

Designing Interface Animation: Improving the User Experience Through Animation by Val Head
Overview
Vue offers some abstractions that can help work with transitions and animations, particularly in response to something changing. Some
of these abstractions include:

Hooks for components entering and leaving the DOM, in both CSS and JS, using the built-in <transition> component.
Transition Modes so that you can orchestrate ordering during a transition.
Hooks for when multiple elements are updating in position, with FLIP techniques applied under the hood to increase performance,
using the <transition-group> component.
Transitioning different states in an application, with watchers .

We will cover all of these and more in the next three sections in this Guide. However, aside from these useful API offerings, it's worth
mentioning that the class and style declarations we covered earlier can be used to apply animations and transitions as well, for more
simple use cases.

In this next section, we'll go over some web animation and transitions basics, and link off to some resources for further exploration. If
you're already familiar with web animation and how those principles might work with some of Vue's directives, feel free to skip this next
section. For anyone else looking to learn a little more about web animation basics before diving in, read on.

Class-based Animations & Transitions


Though the <transition> component can be wonderful for components entering and leaving, you can also activate an animation
without mounting a component, by adding a conditional class.
1 <div id="demo">
2 Push this button to do something you shouldn't be doing:<br />
3
4 <div :class="{ shake: noActivated }">
5 <button @click="noActivated = true">Click me</button>
6 <span v-if="noActivated">Oh no!</span>
7 </div>
8 </div>

1 .shake {
2 animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
3 transform: translate3d(0, 0, 0);
4 backface-visibility: hidden;
5 perspective: 1000px;
6 }
7
8 @keyframes shake {
9 10%,
10 90% {
11 transform: translate3d(-1px, 0, 0);
12 }
13
14 20%,
15 80% {
16 transform: translate3d(2px, 0, 0);
17 }
18
19 30%,
20 50%,
21 70% {
22 transform: translate3d(-4px, 0, 0);
23 }
24
25 40%,
26 60% {
27 transform: translate3d(4px, 0, 0);
28 }
29 }

1 const Demo = {
2 data() {
3 return {
4 noActivated: false
5 }
6 }
7 }
8
9 Vue.createApp(Demo).mount('#demo')

Transitions with Style Bindings


Some transition effects can be applied by interpolating values, for instance by binding a style to an element while an interaction occurs.
Take this example for instance:

1 <div id="demo">
2 <div
3 @mousemove="xCoordinate"
4 :style="{ backgroundColor: `hsl(${x}, 80%, 50%)` }"
5 class="movearea"
6 >
7 <h3>Move your mouse across the screen...</h3>
8 <p>x: {{x}}</p>
9 </div>
10 </div>
1 .movearea {
2 transition: 0.2s background-color ease;
3 }

1 const Demo = {
2 data() {
3 return {
4 x: 0
5 }
6 },
7 methods: {
8 xCoordinate(e) {
9 this.x = e.clientX
10 }
11 }
12 }
13
14 Vue.createApp(Demo).mount('#demo')

In this example, we are creating animation through the use of interpolation, attached to the mouse movement. The CSS transition is
applied to the element as well, to let the element know what kind of easing to use while it's updating.

Performance
You may notice that the animations shown above are using things like transforms , and applying strange properties like perspective -
why were they built that way instead of just using margin and top etc?

We can create extremely smooth animations on the web by being aware of performance. We want to hardware accelerate elements
when we can, and use properties that don't trigger repaints. Let's go over some of how we can accomplish this.
Transform and Opacity
We can check resources like CSS-Triggers to see which properties will trigger repaints if we animate them. Here, if you look
under transform , you will see:

Changing transform does not trigger any geometry changes or painting, which is very good. This means that the operation can likely
be carried out by the compositor thread with the help of the GPU.

Opacity behaves similarly. Thus, they are ideal candidates for movement on the web.

Hardware Acceleration
Properties such as perspective , backface-visibility , and transform: translateZ(x) will allow the browser to know you need
hardware acceleration.

If you wish to hardware-accelerate an element, you can apply any of these properties (not all are necessary, only one):

1 perspective: 1000px;
2 backface-visibility: hidden;
3 transform: translateZ(0);

Many JS libraries like GreenSock will assume you want hardware acceleration and will apply them by default, so you do not need to set
them manually.
Timing
For simple UI transitions, meaning from just one state to another with no intermediary states, it's common to use timings between 0.1s
and 0.4s, and most folks find that 0.25s tends to be a sweet spot. Can you use that timing for everything? No, not really. If you have
something that needs to move a greater distance or has more steps or state changes, 0.25s is not going to work as well and you will
have to be much more intentional, and the timing will need to be more unique. That doesn't mean you can't have nice defaults that you
repeat within your application, though.

You may also find that entrances look better with slightly more time than an exit. The user typically is being guided during the entrance,
and is a little less patient upon exit because they want to go on their way.

Easing
Easing is an important way to convey depth in an animation. One of the most common mistakes newcomers to animation make is to
use ease-in for entrances, and ease-out for exits. You'll actually need the opposite.

If we were to apply these states to a transition, it would look something like this:

1 .button {
2 background: #1b8f5a;
3 /* applied to the initial state, so this transition will be applied to the return state */
4 transition: background 0.25s ease-in;
5 }
6
7 .button:hover {
8 background: #3eaf7c;
9 /* applied to the hover state, so this transition will be applied when a hover is triggered */
10 transition: background 0.35s ease-out;
11 }

Easing can also convey the quality of material being animated. Take this pen for example, which ball do you think is hard and which is
soft?

You can get a lot of unique effects and make your animation very stylish by adjusting your easing. CSS allows you to modify this by
adjusting a cubic bezier property, this playground by Lea Verou is very helpful for exploring this.

Though you can achieve great effects for simple animation with the two handles the cubic-bezier ease offers, JavaScript allows multiple
handles, and therefore, allows for much more variance.
Value

Value
Progress Progress

CSS - limited handles JS - multiple handles


Take a bounce, for instance. In CSS we have to declare each keyframe, up and down. In JavaScript, we can express all of that
movement within the ease, by declaring bounce in the GreenSock API (GSAP) (other JS libraries have other types of easing
defaults).

Here is the code used for a bounce in CSS (example from animate.css):
1 @keyframes bounceInDown {
2 from,
3 60%,
4 75%,
5 90%,
6 to {
7 animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
8 }
9
10 0% {
11 opacity: 0;
12 transform: translate3d(0, -3000px, 0) scaleY(3);
13 }
14
15 60% {
16 opacity: 1;
17 transform: translate3d(0, 25px, 0) scaleY(0.9);
18 }
19
20 75% {
21 transform: translate3d(0, -10px, 0) scaleY(0.95);
22 }
23
24 90% {
25 transform: translate3d(0, 5px, 0) scaleY(0.985);
26 }
27
28 to {
29 transform: translate3d(0, 0, 0);
30 }
31 }
32
33 .bounceInDown {
34 animation-name: bounceInDown;
35 }
And here is the same bounce in JS using GreenSock:

1 gsap.from(element, { duration: 1, ease: 'bounce.out', y: -500 })

We'll be using GreenSock in some of the examples in the sections following. They have a great ease visualizer that will help you build
nicely crafted eases.

# Further Reading

Designing Interface Animation: Improving the User Experience Through Animation by Val Head
Animation at Work by Rachel Nabors
Introduction

Why Composition API?

Note

Reaching this far in the documentation, you should already be familiar with both the basics of Vue and creating components.

Watch a free video about the Composition API on Vue Mastery

Creating Vue components allows us to extract repeatable parts of the interface coupled with its functionality into reusable pieces of
code. This alone can get our application pretty far in terms of maintainability and flexibility. However, our collective experience has
proved that this alone might not be enough, especially when your application is getting really big – think several hundred components.
When dealing with such large applications, sharing and reusing code becomes especially important.

Let’s imagine that in our app, we have a view to show a list of repositories of a certain user. On top of that, we want to apply search and
filter capabilities. Our component handling this view could look like this:

1 // src/components/UserRepositories.vue
2
3 export default {
4 components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
5 props: {
6 user: {
7 type: String,
8 required: true
9 }
10 },
11 data () {
12 return {
13 repositories: [], // 1
14 filters: { ... }, // 3
15 searchQuery: '' // 2
16 }
17 },
18 computed: {
19 filteredRepositories () { ... }, // 3
20 repositoriesMatchingSearchQuery () { ... }, // 2
21 },
22 watch: {
23 user: 'getUserRepositories' // 1
24 },
25 methods: {
26 getUserRepositories () {
27 // using `this.user` to fetch user repositories
28 }, // 1
29 updateFilters () { ... }, // 3
30 },
31 mounted () {
32 this.getUserRepositories() // 1
33 }
34 }

This component has several responsibilities:

1. Getting repositories from a presumedly external API for that user name and refreshing it whenever the user changes
2. Searching for repositories using a searchQuery string
3. Filtering repositories using a filters object
Organizing logics with component's options ( data , computed , methods , watch ) works in most cases. However, when our
components get bigger, the list of logical concerns also grows. This can lead to components that are hard to read and understand,
especially for people who didn't write them in the first place.
Example presenting a large component where its logical concerns are grouped by colors.

Such fragmentation is what makes it difficult to understand and maintain a complex component. The separation of options obscures the
underlying logical concerns. In addition, when working on a single logical concern, we have to constantly "jump" around option blocks for
the relevant code.

It would be much nicer if we could collocate code related to the same logical concern. And this is exactly what the Composition API
enables us to do.

Basics of Composition API


Now that we know the why we can get to the how. To start working with the Composition API we first need a place where we can
actually use it. In a Vue component, we call this place the setup .
setup Component Option

Watch a free video on setup on Vue Mastery

The new setup component option is executed before the component is created, once the props are resolved, and serves as the
entry point for composition API's.

WARNING

Because the component instance is not yet created when setup is executed, there is no this inside a setup option. This
means, with the exception of props , you won't be able to access any properties declared in the component – local
state, computed properties or methods.

The setup option should be a function that accepts props and context which we will talk about later. Additionally, everything that
we return from setup will be exposed to the rest of our component (computed properties, methods, lifecycle hooks and so on) as well
as to the component's template.

Let’s add setup to our component:

1 // src/components/UserRepositories.vue
2
3 export default {
4 components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
5 props: {
6 user: {
7 type: String,
8 required: true
9 }
10 },
11 setup(props) {
12 console.log(props) // { user: '' }
13
14 return {} // anything returned here will be available for the rest of the component
15 }
16 // the "rest" of the component
17 }

Now let’s start with extracting the first logical concern (marked as "1" in the original snippet).

1. Getting repositories from a presumedly external API for that user name and refreshing it whenever the user changes

We will start with the most obvious parts:

The list of repositories


The function to update the list of repositories
Returning both the list and the function so they are accessible by other component options

1 // src/components/UserRepositories.vue `setup` function


2 import { fetchUserRepositories } from '@/api/repositories'
3
4 // inside our component
5 setup (props) {
6 let repositories = []
7 const getUserRepositories = async () => {
8 repositories = await fetchUserRepositories(props.user)
9 }
10
11 return {
12 repositories,
13 getUserRepositories // functions returned behave the same as methods
14 }
15 }

This is our starting point, except it's not working yet because our repositories variable is not reactive. This means from a user's
perspective, the repository list would remain empty. Let's fix that!

Reactive Variables with ref


In Vue 3.0 we can make any variable reactive anywhere with a new ref function, like this:

1 import { ref } from 'vue'


2
3 const counter = ref(0)

ref takes the argument and returns it wrapped within an object with a value property, which can then be used to access or mutate
the value of the reactive variable:

1 import { ref } from 'vue'


2
3 const counter = ref(0)
4
5 console.log(counter) // { value: 0 }
6 console.log(counter.value) // 0
7
8 counter.value++
9 console.log(counter.value) // 1
Wrapping values inside an object might seem unnecessary but is required to keep the behavior unified across different data types in
JavaScript. That’s because in JavaScript, primitive types like Number or String are passed by value, not by reference:

Having a wrapper object around any value allows us to safely pass it across our whole app without worrying about losing its reactivity
somewhere along the way.

Note

In other words, ref creates a Reactive Reference to our value. The concept of working with References will be used often
throughout the Composition API.

Back to our example, let's create a reactive repositories variable:

1 // src/components/UserRepositories.vue `setup` function


2 import { fetchUserRepositories } from '@/api/repositories'
3 import { ref } from 'vue'
4
5 // in our component
6 setup (props) {
7 const repositories = ref([])
8 const getUserRepositories = async () => {
9 repositories.value = await fetchUserRepositories(props.user)
10 }
11
12 return {
13 repositories,
14 getUserRepositories
15 }
16 }

Done! Now whenever we call getUserRepositories , repositories will be mutated and the view will be updated to reflect the change.
Our component should now look like this:

1 // src/components/UserRepositories.vue
2 import { fetchUserRepositories } from '@/api/repositories'
3 import { ref } from 'vue'
4
5 export default {
6 components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
7 props: {
8 user: {
9 type: String,
10 required: true
11 }
12 },
13 setup (props) {
14 const repositories = ref([])
15 const getUserRepositories = async () => {
16 repositories.value = await fetchUserRepositories(props.user)
17 }
18
19 return {
20 repositories,
21 getUserRepositories
22 }
23 },
24 data () {
25 return {
26 filters: { ... }, // 3
27 searchQuery: '' // 2
28 }
29 },
30 computed: {
31 filteredRepositories () { ... }, // 3
32 repositoriesMatchingSearchQuery () { ... }, // 2
33 },
34 watch: {
35 user: 'getUserRepositories' // 1
36 },
37 methods: {
38 updateFilters () { ... }, // 3
39 },
40 mounted () {
41 this.getUserRepositories() // 1
42 }
43 }

We have moved several pieces of our first logical concern into the setup method, nicely put close to each other. What’s left is
calling getUserRepositories in the mounted hook and setting up a watcher to do that whenever the user prop changes.

We will start with the lifecycle hook.

Lifecycle Hook Registration Inside setup


To make Composition API feature-complete compared to Options API, we also need a way to register lifecycle hooks inside setup .
This is possible thanks to several new functions exported from Vue. Lifecycle hooks on composition API have the same name as for
Options API but are prefixed with on : i.e. mounted would look like onMounted .
These functions accept a callback that will be executed when the hook is called by the component.

Let’s add it to our setup function:

1 // src/components/UserRepositories.vue `setup` function


2 import { fetchUserRepositories } from '@/api/repositories'
3 import { ref, onMounted } from 'vue'
4
5 // in our component
6 setup (props) {
7 const repositories = ref([])
8 const getUserRepositories = async () => {
9 repositories.value = await fetchUserRepositories(props.user)
10 }
11
12 onMounted(getUserRepositories) // on `mounted` call `getUserRepositories`
13
14 return {
15 repositories,
16 getUserRepositories
17 }
18 }

Now we need to react to the changes made to the user prop. For that we will use the standalone watch function.

Reacting to Changes with watch


Just like how we set up a watcher on the user property inside our component using the watch option, we can do the same using
the watch function imported from Vue. It accepts 3 arguments:

A Reactive Reference or getter function that we want to watch


A callback
Optional configuration options

Here’s a quick look at how it works.

1 import { ref, watch } from 'vue'


2
3 const counter = ref(0)
4 watch(counter, (newValue, oldValue) => {
5 console.log('The new counter value is: ' + counter.value)
6 })

Whenever counter is modified, for example counter.value = 5 , the watch will trigger and execute the callback (second argument)
which in this case will log 'The new counter value is: 5' into our console.

Below is the Options API equivalent:

1 export default {
2 data() {
3 return {
4 counter: 0
5 }
6 },
7 watch: {
8 counter(newValue, oldValue) {
9 console.log('The new counter value is: ' + this.counter)
10 }
11 }
12 }

For more details on watch , refer to our in-depth guide.

Let’s now apply it to our example:


1 // src/components/UserRepositories.vue `setup` function
2 import { fetchUserRepositories } from '@/api/repositories'
3 import { ref, onMounted, watch, toRefs } from 'vue'
4
5 // in our component
6 setup (props) {
7 // using `toRefs` to create a Reactive Reference to the `user` property of props
8 const { user } = toRefs(props)
9
10 const repositories = ref([])
11 const getUserRepositories = async () => {
12 // update `props.user` to `user.value` to access the Reference value
13 repositories.value = await fetchUserRepositories(user.value)
14 }
15
16 onMounted(getUserRepositories)
17
18 // set a watcher on the Reactive Reference to user prop
19 watch(user, getUserRepositories)
20
21 return {
22 repositories,
23 getUserRepositories
24 }
25 }

You probably have noticed the use of toRefs at the top of our setup . This is to ensure our watcher will react to changes made to
the user prop.

With those changes in place, we've just moved the whole first logical concern into a single place. We can now do the same with the
second concern – filtering based on searchQuery , this time with a computed property.

Standalone computed properties


Similar to ref and watch , computed properties can also be created outside of a Vue component with the computed function
imported from Vue. Let’s get back to our counter example:

1 import { ref, computed } from 'vue'


2
3 const counter = ref(0)
4 const twiceTheCounter = computed(() => counter.value * 2)
5
6 counter.value++
7 console.log(counter.value) // 1
8 console.log(twiceTheCounter.value) // 2

Here, the computed function returns a read-only Reactive Reference to the output of the getter-like callback passed as the first
argument to computed . In order to access the value of the newly-created computed variable, we need to use the .value property just
like with ref .

Let’s move our search functionality into setup :

1 // src/components/UserRepositories.vue `setup` function


2 import { fetchUserRepositories } from '@/api/repositories'
3 import { ref, onMounted, watch, toRefs, computed } from 'vue'
4
5 // in our component
6 setup (props) {
7 // using `toRefs` to create a Reactive Reference to the `user` property of props
8 const { user } = toRefs(props)
9
10 const repositories = ref([])
11 const getUserRepositories = async () => {
12 // update `props.user` to `user.value` to access the Reference value
13 repositories.value = await fetchUserRepositories(user.value)
14 }
15
16 onMounted(getUserRepositories)
17
18 // set a watcher on the Reactive Reference to user prop
19 watch(user, getUserRepositories)
20
21 const searchQuery = ref('')
22 const repositoriesMatchingSearchQuery = computed(() => {
23 return repositories.value.filter(
24 repository => repository.name.includes(searchQuery.value)
25 )
26 })
27
28 return {
29 repositories,
30 getUserRepositories,
31 searchQuery,
32 repositoriesMatchingSearchQuery
33 }
34 }

We could do the same for other logical concerns but you might be already asking the question – Isn’t this just moving the code to
the setup option and making it extremely big? Well, that’s true. That’s why before moving on with the other responsibilities, we will first
extract the above code into a standalone composition function. Let's start with creating useUserRepositories :

1 // src/composables/useUserRepositories.js
2
3 import { fetchUserRepositories } from '@/api/repositories'
4 import { ref, onMounted, watch } from 'vue'
5
6 export default function useUserRepositories(user) {
7 const repositories = ref([])
8 const getUserRepositories = async () => {
9 repositories.value = await fetchUserRepositories(user.value)
10 }
11
12 onMounted(getUserRepositories)
13 watch(user, getUserRepositories)
14
15 return {
16 repositories,
17 getUserRepositories
18 }
19 }

And then the searching functionality:

1 // src/composables/useRepositoryNameSearch.js
2
3 import { ref, computed } from 'vue'
4
5 export default function useRepositoryNameSearch(repositories) {
6 const searchQuery = ref('')
7 const repositoriesMatchingSearchQuery = computed(() => {
8 return repositories.value.filter(repository => {
9 return repository.name.includes(searchQuery.value)
10 })
11 })
12
13 return {
14 searchQuery,
15 repositoriesMatchingSearchQuery
16 }
17 }

Now having those two functionalities in separate files, we can start using them in our component. Here’s how this can be done:

1 // src/components/UserRepositories.vue
2 import useUserRepositories from '@/composables/useUserRepositories'
3 import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch'
4 import { toRefs } from 'vue'
5
6 export default {
7 components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
8 props: {
9 user: {
10 type: String,
11 required: true
12 }
13 },
14 setup (props) {
15 const { user } = toRefs(props)
16
17 const { repositories, getUserRepositories } = useUserRepositories(user)
18
19 const {
20 searchQuery,
21 repositoriesMatchingSearchQuery
22 } = useRepositoryNameSearch(repositories)
23
24 return {
25 // Since we don’t really care about the unfiltered repositories
26 // we can expose the filtered results under the `repositories` name
27 repositories: repositoriesMatchingSearchQuery,
28 getUserRepositories,
29 searchQuery,
30 }
31 },
32 data () {
33 return {
34 filters: { ... }, // 3
35 }
36 },
37 computed: {
38 filteredRepositories () { ... }, // 3
39 },
40 methods: {
41 updateFilters () { ... }, // 3
42 }
43 }

At this point you probably already know the drill, so let’s skip to the end and migrate the leftover filtering functionality. We don’t really
need to get into the implementation details as it’s not the point of this guide.

1 // src/components/UserRepositories.vue
2 import { toRefs } from 'vue'
3 import useUserRepositories from '@/composables/useUserRepositories'
4 import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch'
5 import useRepositoryFilters from '@/composables/useRepositoryFilters'
6
7 export default {
8 components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
9 props: {
10 user: {
11 type: String,
12 required: true
13 }
14 },
15 setup(props) {
16 const { user } = toRefs(props)
17
18 const { repositories, getUserRepositories } = useUserRepositories(user)
19
20 const {
21 searchQuery,
22 repositoriesMatchingSearchQuery
23 } = useRepositoryNameSearch(repositories)
24
25 const {
26 filters,
27 updateFilters,
28 filteredRepositories
29 } = useRepositoryFilters(repositoriesMatchingSearchQuery)
30
31 return {
32 // Since we don’t really care about the unfiltered repositories
33 // we can expose the end results under the `repositories` name
34 repositories: filteredRepositories,
35 getUserRepositories,
36 searchQuery,
37 filters,
38 updateFilters
39 }
40 }
41 }

And we are done!

Keep in mind that we've only scratched the surface of Composition API and what it allows us to do. To learn more about it, refer to the
in-depth guide.
Setup
This section uses single-file component syntax for code examples

This guide assumes that you have already read the Composition API Introductionand Reactivity Fundamentals. Read that first if you
are new to Composition API.

Arguments
When using the setup function, it will take two arguments:

1. props
2. context

Let's dive deeper into how each argument can be used.

Props
The first argument in the setup function is the props argument. Just as you would expect in a standard component, props inside of
a setup function are reactive and will be updated when new props are passed in.

1 // MyBook.vue
2
3 export default {
4 props: {
5 title: String
6 },
7 setup(props) {
8 console.log(props.title)
9 }
10 }

WARNING

However, because props are reactive, you cannot use ES6 destructuringbecause it will remove props reactivity.

If you need to destructure your props, you can do this by utilizing the toRefs inside of the setup function:

1 // MyBook.vue
2
3 import { toRefs } from 'vue'
4
5 setup(props) {
6 const { title } = toRefs(props)
7
8 console.log(title.value)
9 }

If title is an optional prop, it could be missing from props . In that case, toRefs won't create a ref for title . Instead you'd need to
use toRef :

1 // MyBook.vue
2
3 import { toRef } from 'vue'
4
5 setup(props) {
6 const title = toRef(props, 'title')
7
8 console.log(title.value)
9 }

Context
The second argument passed to the setup function is the context . The context is a normal JavaScript object that exposes three
component properties:

1 // MyBook.vue
2
3 export default {
4 setup(props, context) {
5 // Attributes (Non-reactive object)
6 console.log(context.attrs)
7
8 // Slots (Non-reactive object)
9 console.log(context.slots)
10
11 // Emit Events (Method)
12 console.log(context.emit)
13 }
14 }

The context object is a normal JavaScript object, i.e., it is not reactive, this means you can safely use ES6 destructuring on context .

1 // MyBook.vue
2 export default {
3 setup(props, { attrs, slots, emit }) {
4 ...
5 }
6 }
attrs and slots are stateful objects that are always updated when the component itself is updated. This means you should avoid
destructuring them and always reference properties as attrs.x or slots.x . Also note that
unlike props , attrs and slots are not reactive. If you intend to apply side effects based on attrs or slots changes, you should
do so inside an onUpdated lifecycle hook.

Accessing Component Properties


When setup is executed, the component instance has not been created yet. As a result, you will only be able to access the following
properties:

props
attrs
slots
emit

In other words, you will not have access to the following component options:

data
computed
methods

Usage with Templates


If setup returns an object, the properties on the object can be accessed in the component's template, as well as the properties of
the props passed into setup :
1 <!-- MyBook.vue -->
2 <template>
3 <div>{{ collectionName }}: {{ readersNumber }} {{ book.title }}</div>
4 </template>
5
6 <script>
7 import { ref, reactive } from 'vue'
8
9 export default {
10 props: {
11 collectionName: String
12 },
13 setup(props) {
14 const readersNumber = ref(0)
15 const book = reactive({ title: 'Vue 3 Guide' })
16
17 // expose to template
18 return {
19 readersNumber,
20 book
21 }
22 }
23 }
24 </script>

Note that refs returned from setup are automatically unwrapped when accessed in the template so you shouldn't use .value in
templates.

Usage with Render Functions


setup can also return a render function which can directly make use of the reactive state declared in the same scope:
1 // MyBook.vue
2
3 import { h, ref, reactive } from 'vue'
4
5 export default {
6 setup() {
7 const readersNumber = ref(0)
8 const book = reactive({ title: 'Vue 3 Guide' })
9 // Please note that we need to explicitly expose ref value here
10 return () => h('div', [readersNumber.value, book.title])
11 }
12 }

Usage of this
Inside setup() , this won't be a reference to the current active instance Since setup() is called before other component options
are resolved, this inside setup() will behave quite differently from this in other options. This might cause confusions when
using setup() along other Options API.
Lifecycle Hooks
This guide assumes that you have already read the Composition API Introductionand Reactivity
Fundamentals. Read that first if you are new to Composition API.

Watch a free video about Lifecycle Hooks on Vue Mastery

You can access a component's lifecycle hook by prefixing the lifecycle hook with "on".

The following table contains how the lifecycle hooks are invoked inside of setup():

Options API Hook inside setup

beforeCreate Not needed*

created Not needed*

beforeMount onBeforeMount

mounted onMounted

beforeUpdate onBeforeUpdate

updated onUpdated

beforeUnmount onBeforeUnmount

unmounted onUnmounted
Options API Hook inside setup

errorCaptured onErrorCaptured

renderTracked onRenderTracked

renderTriggered onRenderTriggered

TIP

Because setup is run around the beforeCreate and created lifecycle hooks, you do not
need to explicitly define them. In other words, any code that would be written inside those hooks
should be written directly in the setup function.

These functions accept a callback that will be executed when the hook is called by the component:

1 // MyBook.vue
2
3 export default {
4 setup() {
5 // mounted
6 onMounted(() => {
7 console.log('Component is mounted!')
8 })
9 }
10 }

De
# Mixins

Basics
Mixins distribute reusable functionalities for Vue components. A mixin object can contain any component
options. When a component uses a mixin, all options in the mixin will be "mixed" into the component's
own options.

Example:

1 // define a mixin object


2 const myMixin = {
3 created() {
4 this.hello()
5 },
6 methods: {
7 hello() {
8 console.log('hello from mixin!')
9 }
10 }
11 }
12
13 // define an app that uses this mixin
14 const app = Vue.createApp({
15 mixins: [myMixin]
16 })
17
18 app.mount('#mixins-basic') // => "hello from mixin!"

Option Merging
When a mixin and the component itself contain overlapping options, they will be "merged" using
appropriate strategies.

For example, data objects undergo a recursive merge, with the component's data taking priority in cases
of conflicts.

1 const myMixin = {
2 data() {
3 return {
4 message: 'hello',
5 foo: 'abc'
6 }
7 }
8 }
9
10 const app = Vue.createApp({
11 mixins: [myMixin],
12 data() {
13 return {
14 message: 'goodbye',
15 bar: 'def'
16 }
17 },
18 created() {
19 console.log(this.$data) // => { message: "goodbye", foo: "abc", bar: "def" }
20 }
21 })
Hook functions with the same name are merged into an array so that all of them will be called. Mixin
hooks will be called before the component's own hooks.

1 const myMixin = {
2 created() {
3 console.log('mixin hook called')
4 }
5 }
6
7 const app = Vue.createApp({
8 mixins: [myMixin],
9 created() {
10 console.log('component hook called')
11 }
12 })
13
14 // => "mixin hook called"
15 // => "component hook called"

Options that expect object values, for example methods , components and directives , will be merged
into the same object. The component's options will take priority when there are conflicting keys in these
objects:

1 const myMixin = {
2 methods: {
3 foo() {
4 console.log('foo')
5 },
6 conflicting() {
7 console.log('from mixin')
8 }
9 }
10 }
11
12 const app = Vue.createApp({
13 mixins: [myMixin],
14 methods: {
15 bar() {
16 console.log('bar')
17 },
18 conflicting() {
19 console.log('from self')
20 }
21 }
22 })
23
24 const vm = app.mount('#mixins-basic')
25
26 vm.foo() // => "foo"
27 vm.bar() // => "bar"
28 vm.conflicting() // => "from self"

Global Mixin
You can also apply a mixin globally for a Vue application:

1 const app = Vue.createApp({


2 myOption: 'hello!'
3 })
4
5 // inject a handler for `myOption` custom option
6 app.mixin({
7 created() {
8 const myOption = this.$options.myOption
9 if (myOption) {
10 console.log(myOption)
11 }
12 }
13 })
14
15 app.mount('#mixins-global') // => "hello!"

Use with caution! Once you apply a mixin globally, it will affect every component instance created
afterwards in the given app (for example, child components):

1 const app = Vue.createApp({


2 myOption: 'hello!'
3 })
4
5 // inject a handler for `myOption` custom option
6 app.mixin({
7 created() {
8 const myOption = this.$options.myOption
9 if (myOption) {
10 console.log(myOption)
11 }
12 }
13 })
14
15 // add myOption also to child component
16 app.component('test-component', {
17 myOption: 'hello from component!'
18 })
19
20 app.mount('#mixins-global')
21
22 // => "hello!"
23 // => "hello from component!"

In most cases, you should only use it for custom option handling like demonstrated in the example
above. It's also a good idea to ship them as Plugins to avoid duplicate application.
Custom Option Merge Strategies
When custom options are merged, they use the default strategy which overwrites the existing value. If
you want a custom option to be merged using custom logic, you need to attach a function
to app.config.optionMergeStrategies :

1 const app = Vue.createApp({})


2
3 app.config.optionMergeStrategies.customOption = (toVal, fromVal) => {
4 // return mergedVal
5 }

The merge strategy receives the value of that option defined on the parent and child instances as the
first and second arguments, respectively. Let's try to check what do we have in these parameters when
we use a mixin:

1 const app = Vue.createApp({


2 custom: 'hello!'
3 })
4
5 app.config.optionMergeStrategies.custom = (toVal, fromVal) => {
6 console.log(fromVal, toVal)
7 // => "goodbye!", undefined
8 // => "hello", "goodbye!"
9 return fromVal || toVal
10 }
11
12 app.mixin({
13 custom: 'goodbye!',
14 created() {
15 console.log(this.$options.custom) // => "hello!"
16 }
17 })

As you can see, in the console we have toVal and fromVal printed first from the mixin and then from
the app . We always return fromVal if it exists, that's why this.$options.custom is set to hello! in
the end. Let's try to change a strategy to always return a value from the child instance:

1 const app = Vue.createApp({


2 custom: 'hello!'
3 })
4
5 app.config.optionMergeStrategies.custom = (toVal, fromVal) => toVal || fromVal
6
7 app.mixin({
8 custom: 'goodbye!',
9 created() {
10 console.log(this.$options.custom) // => "goodbye!"
11 }
12 })

Precautions
In Vue 2, mixins were the primary tool to abstract parts of component logic into reusable chunks.
However, they have a few issues:

Mixins are conflict-prone: Since properties from each feature are merged into the same component,
you still have to know about every other feature to avoid property name conflicts and for debugging.
Reusability is limited: we cannot pass any parameters to the mixin to change its logic which reduces
their flexibility in terms of abstracting logic

To address these issues, we added a new way to organize code by logical concerns: the Composition
API.
Custom Directives

Intro
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. Note that in Vue, the primary form of code reuse and abstraction is components - however, there may be cases where you
need some low-level DOM access on plain elements, and this is where custom directives would still be useful. An example would be
focusing on an input element, like this one:

When the page loads, that element gains focus (note: autofocus doesn't work on mobile Safari). In fact, if you haven't clicked on
anything else since visiting this page, the input above should be focused now. Also, you can click on the Rerun button and input will be
focused.

Now let's build the directive that accomplishes this:

1 const app = Vue.createApp({})


2 // Register a global custom directive called `v-focus`
3 app.directive('focus', {
4 // When the bound element is mounted into the DOM...
5 mounted(el) {
6 // Focus the element
7 el.focus()
8 }
9 })

If you want to register a directive locally instead, components also accept a directives option:
1 directives: {
2 focus: {
3 // directive definition
4 mounted(el) {
5 el.focus()
6 }
7 }
8 }

Then in a template, you can use the new v-focus attribute on any element, like this:

1 <input v-focus />

Hook Functions
A directive definition object can provide several hook functions (all optional):

created : called before the bound element's attributes or event listeners are applied. This is useful in cases where the directive
needs to attach event listeners that must be called before normal v-on event listeners.

beforeMount : called when the directive is first bound to the element and before parent component is mounted.

mounted : called when the bound element's parent component is mounted.

beforeUpdate : called before the containing component's VNode is updated

Note

We'll cover VNodes in more detail later, when we discuss render functions.
updated : called after the containing component's VNode and the VNodes of its children have updated.

beforeUnmount : called before the bound element's parent component is unmounted

unmounted : called only once, when the directive is unbound from the element and the parent component is unmounted.

You can check the arguments passed into these hooks (i.e. el , binding , vnode , and prevVnode ) in Custom Directive API

Dynamic Directive Arguments


Directive arguments can be dynamic. For example, in v-mydirective:[argument]="value" , the argument can be updated based on
data properties in our component instance! This makes our custom directives flexible for use throughout our application.

Let's say you want to make a custom directive that allows you to pin elements to your page using fixed positioning. We could create a
custom directive where the value updates the vertical positioning in pixels, like this:

1 <div id="dynamic-arguments-example" class="demo">


2 <p>Scroll down the page</p>
3 <p v-pin="200">Stick me 200px from the top of the page</p>
4 </div>

1 const app = Vue.createApp({})


2
3 app.directive('pin', {
4 mounted(el, binding) {
5 el.style.position = 'fixed'
6 // binding.value is the value we pass to directive - in this case, it's 200
7 el.style.top = binding.value + 'px'
8 }
9 })
10
11 app.mount('#dynamic-arguments-example')

This would pin the element 200px from the top of the page. But what happens if we run into a scenario when we need to pin the element
from the left, instead of the top? Here's where a dynamic argument that can be updated per component instance comes in very handy:

1 <div id="dynamicexample">
2 <h3>Scroll down inside this section ↓</h3>
3 <p v-pin:[direction]="200">I am pinned onto the page at 200px to the left.</p>
4 </div>

1 const app = Vue.createApp({


2 data() {
3 return {
4 direction: 'right'
5 }
6 }
7 })
8
9 app.directive('pin', {
10 mounted(el, binding) {
11 el.style.position = 'fixed'
12 // binding.arg is an argument we pass to directive
13 const s = binding.arg || 'top'
14 el.style[s] = binding.value + 'px'
15 }
16 })
17
18 app.mount('#dynamic-arguments-example')

Result:
Our custom directive is now flexible enough to support a few different use cases. To make it even more dynamic, we can also allow to
modify a bound value. Let's create an additional property pinPadding and bind it to the <input type="range">

1 <div id="dynamicexample">
2 <h2>Scroll down the page</h2>
3 <input type="range" min="0" max="500" v-model="pinPadding">
4 <p v-pin:[direction]="pinPadding">Stick me {{ pinPadding + 'px' }} from the {{ direction }} of the page</p>
5 </div>

1 const app = Vue.createApp({


2 data() {
3 return {
4 direction: 'right',
5 pinPadding: 200
6 }
7 }
8 })

Now let's extend our directive logic to recalculate the distance to pin on component update:

1 app.directive('pin', {
2 mounted(el, binding) {
3 el.style.position = 'fixed'
4 const s = binding.arg || 'top'
5 el.style[s] = binding.value + 'px'
6 },
7 updated(el, binding) {
8 const s = binding.arg || 'top'
9 el.style[s] = binding.value + 'px'
10 }
11 })
Result:

Function Shorthand
In previous example, you may want the same behavior on mounted and updated , but don't care about the other hooks. You can do it
by passing the callback to directive:

1 app.directive('pin', (el, binding) => {


2 el.style.position = 'fixed'
3 const s = binding.arg || 'top'
4 el.style[s] = binding.value + 'px'
5 })

Object Literals
If your directive needs multiple values, you can also pass in a JavaScript object literal. Remember, directives can take any valid
JavaScript expression.

1 <div v-demo="{ color: 'white', text: 'hello!' }"></div>

1 app.directive('demo', (el, binding) => {


2 console.log(binding.value.color) // => "white"
3 console.log(binding.value.text) // => "hello!"
4 })
Usage on Components
When used on components, custom directive will always apply to component's root node, similarly to non-prop attributes.

1 <my-component v-demo="test"></my-component>

1 app.component('my-component', {
2 template: `
3 <div> // v-demo directive will be applied here
4 <span>My component content</span>
5 </div>
6 `
7 })

Unlike attributes, directives can't be passed to a different element with v-bind="$attrs" .

With fragments support, components can potentially have more than one root nodes. When applied to a multi-root component, directive
will be ignored and the warning will be thrown.
Teleport
Learn how to use teleport with a free lesson on Vue School

Vue encourages us to build our UIs by encapsulating UI and related behavior into components. We can nest them inside one another to
build a tree that makes up an application UI.

However, sometimes a part of a component's template belongs to this component logically, while from a technical point of view, it would
be preferable to move this part of the template somewhere else in the DOM, outside of the Vue app.

A common scenario for this is creating a component that includes a full-screen modal. In most cases, you'd want the modal's logic to live
within the component, but the positioning of the modal quickly becomes difficult to solve through CSS, or requires a change in
component composition.

Consider the following HTML structure.

1 <body>
2 <div style="position: relative;">
3 <h3>Tooltips with Vue 3 Teleport</h3>
4 <div>
5 <modal-button></modal-button>
6 </div>
7 </div>
8 </body>

Let's take a look at modal-button .


The component will have a button element to trigger the opening of the modal, and a div element with a class of .modal , which
will contain the modal's content and a button to self-close.

1 const app = Vue.createApp({});


2
3 app.component('modal-button', {
4 template: `
5 <button @click="modalOpen = true">
6 Open full screen modal!
7 </button>
8
9 <div v-if="modalOpen" class="modal">
10 <div>
11 I'm a modal!
12 <button @click="modalOpen = false">
13 Close
14 </button>
15 </div>
16 </div>
17 `,
18 data() {
19 return {
20 modalOpen: false
21 }
22 }
23 })

When using this component inside the initial HTML structure, we can see a problem - the modal is being rendered inside the deeply
nested div and the position: absolute of the modal takes the parent relatively positioned div as reference.

Teleport provides a clean way to allow us to control under which parent in our DOM we want a piece of HTML to be rendered, without
having to resort to global state or splitting this into two components.

Let's modify our modal-button to use <teleport> and tell Vue "teleport this HTML tothe "body" tag".
1 app.component('modal-button', {
2 template: `
3 <button @click="modalOpen = true">
4 Open full screen modal! (With teleport!)
5 </button>
6
7 <teleport to="body">
8 <div v-if="modalOpen" class="modal">
9 <div>
10 I'm a teleported modal!
11 (My parent is "body")
12 <button @click="modalOpen = false">
13 Close
14 </button>
15 </div>
16 </div>
17 </teleport>
18 `,
19 data() {
20 return {
21 modalOpen: false
22 }
23 }
24 })

As a result, once we click the button to open the modal, Vue will correctly render the modal's content as a child of the body tag.

Using with Vue components


If <teleport> contains a Vue component, it will remain a logical child component of the <teleport> 's parent:

1 const app = Vue.createApp({


2 template: `
3 <h1>Root instance</h1>
4 <parent-component />
5 `
6 })
7
8 app.component('parent-component', {
9 template: `
10 <h2>This is a parent component</h2>
11 <teleport to="#endofbody">
12 <child-component name="John" />
13 </teleport>
14 `
15 })
16
17 app.component('child-component', {
18 props: ['name'],
19 template: `
20 <div>Hello, {{ name }}</div>
21 `
22 })

In this case, even when child-component is rendered in the different place, it will remain a child of parent-component and will receive
a name prop from it.

This also means that injections from a parent component work as expected, and that the child component will be nested below the
parent component in the Vue Devtools, instead of being placed where the actual content moved to.

Using multiple teleports on the same target


A common use case scenario would be a reusable <Modal> component of which there might be multiple instances active at the same
time. For this kind of scenario, multiple <teleport> components can mount their content to the same target element. The order will be
a simple append - later mounts will be located after earlier ones within the target element.
1 <teleport to="#modals">
2 <div>A</div>
3 </teleport>
4 <teleport to="#modals">
5 <div>B</div>
6 </teleport>
7
8 <!-- result-->
9 <div id="modals">
10 <div>A</div>
11 <div>B</div>
12 </div>

You can check <teleport> component options in the API reference.


Routing

Official Router
For most Single Page Applications, it's recommended to use the officially-supported vue-router library . For more details, see vue-
router's documentation .

Simple Routing from Scratch


If you only need very simple routing and do not wish to involve a full-featured router library, you can do so by dynamically rendering a
page-level component like this:

1 const NotFoundComponent = { template: '<p>Page not found</p>' }


2 const HomeComponent = { template: '<p>Home page</p>' }
3 const AboutComponent = { template: '<p>About page</p>' }
4
5 const routes = {
6 '/': HomeComponent,
7 '/about': AboutComponent
8 }
9
10 const SimpleRouter = {
11 data: () => ({
12 currentRoute: window.location.pathname
13 }),
14
15 computed: {
16 CurrentComponent() {
17 return routes[this.currentRoute] || NotFoundComponent
18 }
19 },
20
21 render() {
22 return Vue.h(this.CurrentComponent)
23 }
24 }
25
26 Vue.createApp(SimpleRouter).mount('#app')

Combined with the History API , you can build a very basic but fully-functional client-side router. To see that in practice, check out this
example app .

# Integrating 3rd-Party Routers

If there's a 3rd-party router you prefer to use, such as Page.js or Director , integration is similarly straightforward . Here's
a complete example using Page.js.
State Management

Official Flux-Like Implementation


Large applications can often grow in complexity, due to multiple pieces of state scattered across many components and the interactions
between them. To solve this problem, Vue offers Vuex , our own Elm-inspired state management library. It even integrates into vue-
devtools , providing zero-setup access to time travel debugging .

Information for React Developers


If you're coming from React, you may be wondering how vuex compares to redux , the most popular Flux implementation in that
ecosystem. Redux is actually view-layer agnostic, so it can easily be used with Vue via simple bindings . Vuex is different in that
it knows it's in a Vue app. This allows it to better integrate with Vue, offering a more intuitive API and improved development experience.

Simple State Management from Scratch


It is often overlooked that the source of truth in Vue applications is the reactive data object - a component instance only proxies access
to it. Therefore, if you have a piece of state that should be shared by multiple instances, you can use a reactive method to make an
object reactive:

1 const sourceOfTruth = Vue.reactive({


2 message: 'Hello'
3 })
4
5 const appA = Vue.createApp({
6 data() {
7 return sourceOfTruth
8 }
9 }).mount('#app-a')
10
11 const appB = Vue.createApp({
12 data() {
13 return sourceOfTruth
14 }
15 }).mount('#app-b')

1 <div id="app-a">App A: {{ message }}</div>


2
3 <div id="app-b">App B: {{ message }}</div>

Now whenever sourceOfTruth is mutated, both appA and appB will update their views automatically. We have a single source of
truth now, but debugging would be a nightmare. Any piece of data could be changed by any part of our app at any time, without leaving
a trace.

1 const appB = Vue.createApp({


2 data() {
3 return sourceOfTruth
4 },
5 mounted() {
6 sourceOfTruth.message = 'Goodbye' // both apps will render 'Goodbye' message now
7 }
8 }).mount('#app-b')

To help solve this problem, we can adopt a store pattern:


1 const store = {
2 debug: true,
3
4 state: Vue.reactive({
5 message: 'Hello!'
6 }),
7
8 setMessageAction(newValue) {
9 if (this.debug) {
10 console.log('setMessageAction triggered with', newValue)
11 }
12
13 this.state.message = newValue
14 },
15
16 clearMessageAction() {
17 if (this.debug) {
18 console.log('clearMessageAction triggered')
19 }
20
21 this.state.message = ''
22 }
23 }

Notice all actions that mutate the store's state are put inside the store itself. This type of centralized state management makes it easier
to understand what type of mutations could happen and how they are triggered. Now when something goes wrong, we'll also have a log
of what happened leading up to the bug.

In addition, each instance/component can still own and manage its own private state:

1 <div id="app-a">{{sharedState.message}}</div>
2
3 <div id="app-b">{{sharedState.message}}</div>
1 const appA = Vue.createApp({
2 data() {
3 return {
4 privateState: {},
5 sharedState: store.state
6 }
7 },
8 mounted() {
9 store.setMessageAction('Goodbye!')
10 }
11 }).mount('#app-a')
12
13 const appB = Vue.createApp({
14 data() {
15 return {
16 privateState: {},
17 sharedState: store.state
18 }
19 }
20 }).mount('#app-b')
TIP
You should never replace the original state object in your actions - the components and the store need to share reference to the
same object in order for mutations to be observed.

As we continue developing the convention, where components are never allowed to directly mutate state that belongs to a store but
should instead dispatch events that notify the store to perform actions, we eventually arrive at the Flux architecture. The benefit of this
convention is we can record all state mutations happening to the store and implement advanced debugging helpers such as mutation
logs, snapshots, and history re-rolls / time travel.

This brings us full circle back to Vuex , so if you've read this far it's probably time to try it out!
Server-Side Rendering

The Complete SSR Guide


We have created a standalone guide for creating server-rendered Vue applications. This is a very in-depth guide for those who are
already familiar with client-side Vue development, server-side Node.js development and webpack. Check it out at ssr.vuejs.org .

Nuxt.js
Properly configuring all the discussed aspects of a production-ready server-rendered app can be a daunting task. Luckily, there is an
excellent community project that aims to make all of this easier: Nuxt.js . Nuxt.js is a higher-level framework built on top of the Vue
ecosystem which provides an extremely streamlined development experience for writing universal Vue applications. Better yet, you can
even use it as a static site generator (with pages authored as single-file Vue components)! We highly recommend giving it a try.

Quasar Framework SSR + PWA


Quasar Framework will generate an SSR app (with optional PWA handoff) that leverages its best-in-class build system, sensible
configuration and developer extensibility to make designing and building your idea a breeze. With over one hundred specific "Material
Design 2.0"-compliant components, you can decide which ones to execute on the server, which are available in the browser, and even
manage the <meta> tags of your site. Quasar is a node.js and webpack based development environment that supercharges and
streamlines rapid development of SPA, PWA, SSR, Electron, Capacitor and Cordova apps—all from one codebase.
Introduction
Like the Fetch API, Axios is a promise-based HTTP client for making requests to external servers from the
browser. If you have worked with jQuery, you may already know about its $.ajax() function which has been
a popular choice for frontend developers over the native XML HTTP Request (XHR) interface. The Axios library
wraps the complex XHR syntax and provides an abstract and declarative way to make requests from the
browser as well as in a node environment.

We have already discussed about how we can make HTTP requests using Axios to get data from the server
using axios.get() function and post data to the server using axios.post() function in an earlier guide.
In this guide, we will take a deeper route and learn more about other cool features Axios provides.

Making Concurrent HTTP Requests


More often than not, you will come across a scenario where you'll have to make requests from two endpoints for
a particular task. Let’s consider that you are working with a CMS REST API and you have to get the current
user's data as well as the permissions for that user. You'll probably do something like what is shown below:

jsx
1 class User extends Component {
2 constructor(props) {
3 super(props);
4 this.state = {
5 user: {
6 data: {},
7 permissions: {}
8 }
9 };
10 }
11
12 getUserData = async () => {
13 try {
14 const {data} = await axios.get(`${ROOT_URL}/profile/${this.props.activeUserId}
15 return data;
16 } catch (err) {
17 console.log(err.message);
18 }
19 }
20
21 getPermissions = async () => {
22 try {
23 const {data} = await axios.get(`${ROOT_URL}/permissions/${this.props.activeUse
24 return data;
25 } catch (err) {
26 console.log(err.message);
27 }
28 }
29
30 async componentDidMount() {
31 const userData = await this.getUserData();
32 const userPermissions = await this.getPermissions();
33 this.setState(
34 user: {
35 data: userData,
36 permissions: userPermissions
37 }
38 );
39 }
40
41 render() {
42 // render the data
43 }
44
45 }

Instead of making the requests twice, we can call the endpoints simultaneously using
the axios.all() function.

jsx
1 class User extends Component {
2 // ...
3
4 getUserData = () => axios.get(`${ROOT_URL}/profile/${this.props.activeUserId}`);
5
6 getPermissions = () => axios.get(`${ROOT_URL}/permissions/${this.props.activeUserId}`)
7
8 async componentDidMount() {
9 try {
10 const [userData, userPermissions] = await axios.all([ this.getUserData(), this
11 this.setState(
12 user: {
13 data: userData.data,
14 permissions: userPermissions.data
15 }
16 );
17 }
18 catch (err) {
19 console.log(err.message);
20 }
21
22 }
23
24 // ...
25 }

Note that I have used async-await syntax to make the code more readable, instead of handling the
promises with .then() and .catch() . Having said that, it's really up to you which syntax you prefer, both
do the same job of handling promises.

axios.all() accepts an array of Axios requests, and returns an array that contains the responses from
each Axios request. The problem here is that even if one of the requests fails, by default, all the other requests
fail as well and the error from the first failed request will be logged in the catch() block.

To get around this problem, we can simply return null from the catch() block of each Axios request. So,
even if one of the requests fail, it will still consider the axios.all() promise to be resolved. The return value
from the failed request will be null , hence we need to have additional checks for if the data in the returned
array is null or not.

jsx
1 class User extends Component {
2 // ...
3
4 getUserData = () => axios.get(`${ROOT_URL}/profile/${this.props.activeUserId}`).catch(
5
6 getPermissions = () => axios.get(`${ROOT_URL}/permissions/${this.props.activeUserId}`)
7
8 async componentDidMount() {
9 try {
10 const [userData, userPermissions] = await axios.all([ this.getUserData(), this
11 this.setState(
12 user: {
13 data: userData && userData.data,
14 permissions: userPermissions && userPermissions.data
15 }
16 );
17 }
18 catch (err) {
19 console.log(err.message);
20 }
21 }
22
23 // ...
24 }

We can further refactor the above code, as follows:

jsx
1 class User extends Component {
2 constructor(props) {
3 super(props);
4 this.state = {
5 user: {
6 data: {},
7 permissions: {}
8 }
9 };
10 }
11
12 async componentDidMount() {
13 const URLs = [ `${ROOT_URL}/profile/${this.props.activeUserId}`, `${ROOT_URL}/perm
14
15 const requests = URLs.map(URL => axios.get(URL).catch(err => null));
16
17 try {
18 const [userData, userPermissions] = await axios.all(requests);
19 this.setState(
20 user: {
21 data: userData && userData.data,
22 permissions: userPermissions && userPermissions.data
23 }
24 );
25 }
26 catch (err) {
27 console.log(err.message);
28 }
29 }
30
31 render() {
32 // render the data
33 }
34
35 }

Consuming Arrays from Axios Response


APIs often return an array that contains objects of data. For example, when you want to retrieve all posts from
your CMS. To consume the array, we have to loop over the response using the Array.map() function which
can be done as follows:

jsx
1 class Posts extends Component {
2 constructor(props) {
3 super(props);
4 this.state = { posts: [] }
5 }
6
7 async componentDidMount() {
8 try {
9 const {data} = await axios.get(`${ROOT_URL}/posts`);
10 this.setState({
11 posts: data
12 })
13 } catch (err) {
14 console.log(err.message)
15 }
16 }
17
18 render() {
19 return (
20 <div className="container">
21 { this.state.posts && this.state.posts.length !== 0 ?
22 this.state.posts.map(post => <Card title={post.title}>{post.content}</Card
23 <Loading/> }
24 </div>
25 );
26 }
27 }

The Array.map() function iterates over each element of the array and returns a new array; in our case, the
array contains JSX elements, the <Card /> component. Note that here, I'm using the shorthand version, a
more complete implementation is as follows:

jsx
1 // ...
2 render() {
3 return (
4 <div className="container">
5 { this.state.posts && this.state.posts.length !== 0 ?
6 this.state.posts.map((post, index) => {
7 const { title, content } = post;
8 return <Card title={title}>{content}</Card>;
9 }) :
10 <Loading/> }
11 </div>
12 );
13 }
14 //..

For each element in the array, the map() function provides us with an anonymous function that accepts two
arguments, the item itself and an optional index argument which contains the position value of the current item.
We can also do some transformation of data before returning it with JSX. For example we can transform the title
to uppercase, as follows:

jsx
1 // ...
2 this.state.posts.map((post, index) => {
3 const { title, content } = post;
4 const transformedTitle = title.toUpperCase();
5 return <Card title={transformedTitle}>{content}</Card>;
6 })
7 //..

For conditional rendering in JSX, you cannot use an if-else block. Hence, we have used the ternary
operators. Also notice that, when we try to run the above code in the browser, we get a warning message in the
console which says: Each child in an array or iterator should have a unique "key" prop.

The key prop is used by React to keep track of items in an array. In the above
example, this.state.posts.map() will result in an array, hence each JSX element must have a key
prop associated with it. Not including a key prop will lead to unexpected results and bugs.

In our case, if we do not specify the key prop in our <Card /> component, React wouldn't know how to
keep track of the posts and, hence, when the state changes it would re-render the whole array again instead of
updating the changes. This is undesirable because it will affect the performance of the application. Therefore,
it's important to have at least one unique key value (in our case, post id) for array item.

jsx
1 //...
2 this.state.posts.map((post, index) => {
3 const { id, title, content } = post;
4 return <Card key={id} title={title}>{content}</Card>;
5 })
6 //...

Aborting or Cancelling an Axios Request


You can also cancel or abort a request, if you no longer require the data. To cancel a request, we need to create
a cancel token using the CancelToken.source() factory method. Let’s say that we want to cancel the
request when the user navigates from the current page to another page, we can write something as follows:

jsx
1 const NavBar = props => (
2 <Nav>
3 <NavItem onClick={() => props.navigate('/home') }> Home </NavItem>
4 <NavItem onClick={() => props.navigate('/about') }> About </NavItem>
5 <NavItem onClick={() => props.navigate('/contact') }> Contact </NavItem>
6 </Nav>
7 )
8
9 class Posts extends Component {
10 constructor(props) {
11 super(props);
12 this.state = { posts: [] }
13 }
14
15 navigate = url => {
16 // cancel the request
17 this.source.cancel('User navigated to different page');
18
19 // assuming we are using React-Router
20 this.props.history.push(url);
21 }
22
23 async componentDidMount() {
24 const CancelToken = axios.CancelToken;
25 // create the source
26 this.source = CancelToken.source();
27 try {
28 const {data} = await axios.get(`${ROOT_URL}/posts`, {
29 cancelToken: this.source.token
30 });
31 this.setState({
32 posts: data
33 })
34 } catch (err) {
35 // check if the request was cancelled
36 if(axios.isCancel(err)) {
37 console.log(err.message);
38 }
39 console.log(err.message)
40 }
41 }
42
43 render() {
44 return (
45 <div className="container">
46 <NavBar navigate={this.navigate}/>
47 { this.state.posts && this.state.posts.length !== 0 ?
48 this.state.posts.map(post => <Card key={post.id} title={post.title}>{post.
49 <Loading/> }
50 </div>
51 );
52 }
53 }

The CancelToken.source factory provides us with two main requirements for cancelling the Axios request,
the cancel token and the cancel() function. We need to pass the cancel token as a config to
the axios.get() function and call the cancel() function whenever we need to cancel the previous Axios
request. We can use the same cancel token for multiple Axios requests.

We can also create a cancel token by passing an executor() function to the CancelToken constructor.

jsx
1 navigate = url => {
2 this.cancelRequest && this.cancelRequest('User navigated to different page');
3
4 // assuming we are using React-Router
5 this.props.history.push(url);
6 }
7
8 async componentDidMount() {
9 const CancelToken = axios.CancelToken;
10 try {
11 const {data} = await axios.get(`${ROOT_URL}/posts`, {
12 cancelToken: new CancelToken(function executor(c) {
13 this.cancelRequest = c;
14 })
15 });
16 this.setState({
17 posts: data
18 })
19 } catch (err) {
20 if(axios.isCancel(err)) {
21 console.log(err.message);
22 }
23 console.log(err.message);
24 }
25 }

Let’s check out another use case for cancelling the request. Consider the scenario where we have a search
component that retrieves the results from the search API. As the user types in the input field, we need to cancel
the previous axios request.

jsx
1 class Search extends Component {
2 constructor(props) {
3 super(props);
4 this.state = { value: null, results: [] };
5 }
6
7 search = async () => {
8 const CancelToken = axios.CancelToken;
9 try {
10 const {data} = await axios.get(`${ROOT_URL}/search/q=${this.state.value}`, {
11 cancelToken: new CancelToken(function executor(c) {
12 this.cancelRequest = c;
13 });
14 });
15 } catch (err) {
16 if(axios.isCancel(thrown)) {
17 console.log(thrown.message);
18 }
19 console.log(err.message)
20 }
21 }
22
23 handleChange = e => {
24 this.cancelRequest && this.cancelRequest();
25 if(e.target.value !== "") {
26 this.setState({ value: e.target.value }, async () => await this.search());
27 }
28 }
29
30 render() {
31 return <input type="text" onChange={this.handleChange} value={this.state.value}/>
32 }
33 }
Here, we are cancelling the request when the value of the input field changes. An important point to note in the
above code is that we are passing a callback as a second parameter to the setState() function. This is
because the state does not change immediately and, hence, to avoid any unexpected outcomes, we are calling
the search() function in the callback instead of calling it directly inside the handleChange() method. In
a more real-world use case, the search input would be debounced but, for brevity purposes, I'm not including it
here.

Conclusion
In this guide, we looked up various important use cases of Axios and how it's really a great library for making
HTTP requests in React (or any other JavaScript Framework like Vue). I hope you had enough of Axios today,
and do checkout the Axios documentation that will be linked in the references.

Please follow my other React guides to learn more. If you have any queries, feel free to ask at Codealphabet
axios
code e pe s
npm v0.21.1
  cdnjs v0.21.1
  build failing
  coverage 94%
  install size 388 kB
  downloads 56M/month
  chat on gitter
  code helpers 141

Promise based HTTP client for the browser and node.js

Table of Contents
Features
Browser Support
Installing
Example
Axios API
Request method aliases
Concurrency (Deprecated)
Creating an instance
Instance methods
Request Config
Response Schema
Config Defaults
Global axios defaults
Custom instance defaults
Config order of precedence
Interceptors
Handling Errors
Cancellation
Using application/x-www-form-urlencoded format
Browser
Node.js
Query string
Form data
Semver
Promises
TypeScript
Resources
Credits
License

Features
Make XMLHttpRequests from the browser
Make http requests from node.js
Supports the Promise API
Intercept request and response
Transform request and response data
Cancel requests
Automatic transforms for JSON data
Client side support for protecting against XSRF

Browser Support

Latest ✔ Latest ✔ Latest ✔ Latest ✔ Latest ✔ 11 ✔


Firefox Chrome IE Edge Safari
83 7 87 7 11 8.1 86 10 9 10.11

10 10.12

11 10.13
TESTING P O WERED BY

Installing
Using npm:

$ npm install axios

Using bower:

$ bower install axios

Using yarn:

$ yarn add axios

Using jsDelivr CDN:

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

Using unpkg CDN:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
Example

note: CommonJS usage


In order to gain the TypeScript typings (for intellisense / autocomplete) while using CommonJS imports with  require()  use the
following approach:

const axios = require('axios').default;

// axios.<method> will now provide autocomplete and parameter typings

Performing a  GET  request

const axios = require('axios');

// Make a request for a user with a given ID


axios.get('/user?ID=12345')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});

// Optionally the request above could also be done as


axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});

// Want to use async/await? Add the `async` keyword to your outer function/method.
async function getUser() {
try {
const response = await axios.get('/user?ID=12345');
console.log(response);
} catch (error) {
console.error(error);
}
}

NOTE:  async/await  is part of ECMAScript 2017 and is not supported in Internet Explorer and older browsers, so use with caution.

Performing a  POST  request

axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
Performing multiple concurrent requests

function getUserAccount() {
return axios.get('/user/12345');
}

function getUserPermissions() {
return axios.get('/user/12345/permissions');
}

Promise.all([getUserAccount(), getUserPermissions()])
.then(function (results) {
const acct = results[0];
const perm = results[1];
});

axios API
Requests can be made by passing the relevant config to  axios .

axios(config)

// Send a POST request


axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
// GET request for remote image in node.js
axios({
method: 'get',
url: 'http://bit.ly/2mTM3nY',
responseType: 'stream'
})
.then(function (response) {
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});

axios(url[, config])

// Send a GET request (default method)


axios('/user/12345');

Request method aliases


For convenience aliases have been provided for all supported request methods.

axios.request(config)

axios.get(url[, config])

axios.delete(url[, config])

axios.head(url[, config])

axios.options(url[, config])

axios.post(url[, data[, config]])

axios.put(url[, data[, config]])


axios.patch(url[, data[, config]])

NOTE

When using the alias methods  url ,  method , and  data  properties don't need to be specified in config.

Concurrency (Deprecated)
Please use  Promise.all  to replace the below functions.

Helper functions for dealing with concurrent requests.

axios.all(iterable) axios.spread(callback)

Creating an instance
You can create a new instance of axios with a custom config.

axios.create([config])

const instance = axios.create({


baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});

Instance methods
The available instance methods are listed below. The specified config will be merged with the instance config.

axios#request(config)

axios#get(url[, config])

axios#delete(url[, config])
axios#head(url[, config])

axios#options(url[, config])

axios#post(url[, data[, config]])

axios#put(url[, data[, config]])

axios#patch(url[, data[, config]])

axios#getUri([config])

Request Config
These are the available config options for making requests. Only the  url  is required. Requests will default to  GET  if  method is not
specified.

{
// `url` is the server URL that will be used for the request
url: '/user',

// `method` is the request method to be used when making the request


method: 'get', // default

// `baseURL` will be prepended to `url` unless `url` is absolute.


// It can be convenient to set `baseURL` for an instance of axios to pass relative URLs
// to methods of that instance.
baseURL: 'https://some-domain.com/api/',

// `transformRequest` allows changes to the request data before it is sent to the server
// This is only applicable for request methods 'PUT', 'POST', 'PATCH' and 'DELETE'
// The last function in the array must return a string or an instance of Buffer, ArrayBuffer,
// FormData or Stream
// You may modify the headers object.
transformRequest: [function (data, headers) {
// Do whatever you want to transform the data
return data;
}],

// `transformResponse` allows changes to the response data to be made before


// it is passed to then/catch
transformResponse: [function (data) {
// Do whatever you want to transform the data

return data;
}],

// `headers` are custom headers to be sent


headers: {'X-Requested-With': 'XMLHttpRequest'},

// `params` are the URL parameters to be sent with the request


// Must be a plain object or a URLSearchParams object
params: {
ID: 12345
},

// `paramsSerializer` is an optional function in charge of serializing `params`


// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function (params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},

// `data` is the data to be sent as the request body


// Only applicable for request methods 'PUT', 'POST', 'DELETE , and 'PATCH'
// When no `transformRequest` is set, must be of one of the following types:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - Browser only: FormData, File, Blob
// - Node only: Stream, Buffer
data: {
firstName: 'Fred'
},

// syntax alternative to send data into the body


// method post
// only the value is sent, not the key
data: 'Country=Brasil&City=Belo Horizonte',

// `timeout` specifies the number of milliseconds before the request times out.
// If the request takes longer than `timeout`, the request will be aborted.
timeout: 1000, // default is `0` (no timeout)

// `withCredentials` indicates whether or not cross-site Access-Control requests


// should be made using credentials
withCredentials: false, // default

// `adapter` allows custom handling of requests which makes testing easier.


// Return a promise and supply a valid response (see lib/adapters/README.md).
adapter: function (config) {
/* ... */
},

// `auth` indicates that HTTP Basic auth should be used, and supplies credentials.
// This will set an `Authorization` header, overwriting any existing
// `Authorization` custom headers you have set using `headers`.
// Please note that only HTTP Basic auth is configurable through this parameter.
// For Bearer tokens and such, use `Authorization` custom headers instead.
auth: {
username: 'janedoe',
password: 's00pers3cret'
},

// `responseType` indicates the type of data that the server will respond with
// options are: 'arraybuffer', 'document', 'json', 'text', 'stream'
// browser only: 'blob'
responseType: 'json', // default

// `responseEncoding` indicates encoding to use for decoding responses (Node.js only)


// Note: Ignored for `responseType` of 'stream' or client-side requests
responseEncoding: 'utf8', // default

// `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
xsrfCookieName: 'XSRF-TOKEN', // default

// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
xsrfHeaderName: 'X-XSRF-TOKEN', // default

// `onUploadProgress` allows handling of progress events for uploads


// browser only
onUploadProgress: function (progressEvent) {
// Do whatever you want with the native progress event
},

// `onDownloadProgress` allows handling of progress events for downloads


// browser only
onDownloadProgress: function (progressEvent) {
// Do whatever you want with the native progress event
},

// `maxContentLength` defines the max size of the http response content in bytes allowed in node.js
maxContentLength: 2000,

// `maxBodyLength` (Node only option) defines the max size of the http request content in bytes allowed
maxBodyLength: 2000,

// `validateStatus` defines whether to resolve or reject the promise for a given


// HTTP response status code. If `validateStatus` returns `true` (or is set to `null`
// or `undefined`), the promise will be resolved; otherwise, the promise will be
// rejected.
validateStatus: function (status) {
return status >= 200 && status < 300; // default
},

// `maxRedirects` defines the maximum number of redirects to follow in node.js.


// If set to 0, no redirects will be followed.
maxRedirects: 5, // default

// `socketPath` defines a UNIX Socket to be used in node.js.


// e.g. '/var/run/docker.sock' to send requests to the docker daemon.
// Only either `socketPath` or `proxy` can be specified.
// If both are specified, `socketPath` is used.
socketPath: null, // default

// `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
// and https requests, respectively, in node.js. This allows options to be added like
// `keepAlive` that are not enabled by default.
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),

// `proxy` defines the hostname, port, and protocol of the proxy server.
// You can also define your proxy using the conventional `http_proxy` and
// `https_proxy` environment variables. If you are using environment variables
// for your proxy configuration, you can also define a `no_proxy` environment
// variable as a comma-separated list of domains that should not be proxied.
// Use `false` to disable proxies, ignoring environment variables.
// `auth` indicates that HTTP Basic auth should be used to connect to the proxy, and
// supplies credentials.
// This will set an `Proxy-Authorization` header, overwriting any existing
// `Proxy-Authorization` custom headers you have set using `headers`.
// If the proxy server uses HTTPS, then you must set the protocol to `https`.
proxy: {
protocol: 'https',
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
},

// `cancelToken` specifies a cancel token that can be used to cancel the request
// (see Cancellation section below for details)
cancelToken: new CancelToken(function (cancel) {
}),

// `decompress` indicates whether or not the response body should be decompressed


// automatically. If set to `true` will also remove the 'content-encoding' header
// from the responses objects of all decompressed responses
// - Node only (XHR cannot turn off decompression)
decompress: true // default

Response Schema
The response for a request contains the following information.

{
// `data` is the response that was provided by the server
data: {},

// `status` is the HTTP status code from the server response


status: 200,

// `statusText` is the HTTP status message from the server response


statusText: 'OK',

// `headers` the HTTP headers that the server responded with


// All header names are lower cased and can be accessed using the bracket notation.
// Example: `response.headers['content-type']`
headers: {},

// `config` is the config that was provided to `axios` for the request
config: {},

// `request` is the request that generated this response


// It is the last ClientRequest instance in node.js (in redirects)
// and an XMLHttpRequest instance in the browser
request: {}
}

When using  then , you will receive the response as follows:


axios.get('/user/12345')
.then(function (response) {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
});

When using  catch , or passing a rejection callback as second parameter of  then , the response will be available through
the  error  object as explained in the Handling Errors section.

Config Defaults
You can specify config defaults that will be applied to every request.

Global axios defaults

axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

Custom instance defaults

// Set config defaults when creating the instance


const instance = axios.create({
baseURL: 'https://api.example.com'
});

// Alter defaults after instance has been created


instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
Config order of precedence
Config will be merged with an order of precedence. The order is library defaults found in lib/defaults.js, then  defaults property of the
instance, and finally  config  argument for the request. The latter will take precedence over the former. Here's an example.

// Create an instance using the config defaults provided by the library


// At this point the timeout config value is `0` as is the default for the library
const instance = axios.create();

// Override timeout default for the library


// Now all requests using this instance will wait 2.5 seconds before timing out
instance.defaults.timeout = 2500;

// Override timeout for this request as it's known to take a long time
instance.get('/longRequest', {
timeout: 5000
});

Interceptors
You can intercept requests or responses before they are handled by  then  or  catch .

// Add a request interceptor


axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});

// Add a response interceptor


axios.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});

If you need to remove an interceptor later you can.

const myInterceptor = axios.interceptors.request.use(function () {/*...*/});


axios.interceptors.request.eject(myInterceptor);

You can add interceptors to a custom instance of axios.

const instance = axios.create();


instance.interceptors.request.use(function () {/*...*/});

Handling Errors

axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});

Using the  validateStatus  config option, you can define HTTP code(s) that should throw an error.

axios.get('/user/12345', {
validateStatus: function (status) {
return status < 500; // Resolve only if the status code is less than 500
}
})

Using  toJSON  you get an object with more information about the HTTP error.

axios.get('/user/12345')
.catch(function (error) {
console.log(error.toJSON());
});

Cancellation
You can cancel a request using a cancel token.

The axios cancel token API is based on the withdrawn cancelable promises proposal.

You can create a cancel token using the  CancelToken.source  factory as shown below:

const CancelToken = axios.CancelToken;


const source = CancelToken.source();

axios.get('/user/12345', {
cancelToken: source.token
}).catch(function (thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}
});

axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})

// cancel the request (the message parameter is optional)


source.cancel('Operation canceled by the user.');

You can also create a cancel token by passing an executor function to the  CancelToken  constructor:

const CancelToken = axios.CancelToken;


let cancel;

axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// An executor function receives a cancel function as a parameter
cancel = c;
})
});

// cancel the request


cancel();

Note: you can cancel several requests with the same cancel token.
Using application/x-www-form-urlencoded format
By default, axios serializes JavaScript objects to  JSON . To send data in the  application/x-www-form-urlencoded  format instead, you can
use one of the following options.

Browser
In a browser, you can use the  URLSearchParams  API as follows:

const params = new URLSearchParams();


params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);

Note that  URLSearchParams  is not supported by all browsers (see caniuse.com), but there is a polyfill available (make sure to polyfill
the global environment).

Alternatively, you can encode data using the  qs  library:

const qs = require('qs');
axios.post('/foo', qs.stringify({ 'bar': 123 }));

Or in another way (ES6),

import qs from 'qs';


const data = { 'bar': 123 };
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
url,
};
axios(options);
Node.js

Query string

In node.js, you can use the  querystring  module as follows:

const querystring = require('querystring');


axios.post('http://something.com/', querystring.stringify({ foo: 'bar' }));

or 'URLSearchParams' from 'url module' as follows:

const url = require('url');


const params = new url.URLSearchParams({ foo: 'bar' });
axios.post('http://something.com/', params.toString());

You can also use the  qs  library.

NOTE

The  qs  library is preferable if you need to stringify nested objects, as the  querystring  method has known issues with that use case
(https://github.com/nodejs/node-v0.x-archive/issues/1665).

Form data

In node.js, you can use the  form-data  library as follows:

const FormData = require('form-data');

const form = new FormData();


form.append('my_field', 'my value');
form.append('my_buffer', new Buffer(10));
form.append('my_file', fs.createReadStream('/foo/bar.jpg'));
axios.post('https://example.com', form, { headers: form.getHeaders() })

Alternatively, use an interceptor:

axios.interceptors.request.use(config => {
if (config.data instanceof FormData) {
Object.assign(config.headers, config.data.getHeaders());
}
return config;
});

Semver
Until axios reaches a  1.0  release, breaking changes will be released with a new minor version. For example  0.5.1 , and  0.5.4  will have
the same API, but  0.6.0  will have breaking changes.

Promises
axios depends on a native ES6 Promise implementation to be supported. If your environment doesn't support ES6 Promises, you
can polyfill.

TypeScript
axios includes TypeScript definitions.

import axios from 'axios';


axios.get('/user?ID=12345');

Resources
Changelog
Upgrade Guide
Ecosystem
Contributing Guide
Code of Conduct

Credits
axios is heavily inspired by the $http service provided in Angular. Ultimately axios is an effort to provide a standalone  $http -like service
for use outside of Angular.

License

You might also like