--- url: /guide/introduction.md --- # Introduction {#introduction} :::info You are reading the documentation for Vue 3! * Vue 2 support has ended on **Dec 31, 2023**. Learn more about [Vue 2 EOL](https://v2.vuejs.org/eol/). * Upgrading from Vue 2? Check out the [Migration Guide](https://v3-migration.vuejs.org/). ::: ## What is Vue? {#what-is-vue} Vue (pronounced /vjuː/, like **view**) is a JavaScript framework for building user interfaces. It builds on top of standard HTML, CSS, and JavaScript and provides a declarative, component-based programming model that helps you efficiently develop user interfaces of any complexity. Here is a minimal example: ```js import { createApp } from 'vue' createApp({ data() { return { count: 0 } } }).mount('#app') ``` ```js import { createApp, ref } from 'vue' createApp({ setup() { return { count: ref(0) } } }).mount('#app') ``` ```vue-html
``` **Result** The above example demonstrates the two core features of Vue: * **Declarative Rendering**: Vue extends standard HTML with a template syntax that allows us to declaratively describe HTML output based on JavaScript state. * **Reactivity**: Vue automatically tracks JavaScript state changes and efficiently updates the DOM when changes happen. You may already have questions - don't worry. We will cover every little detail in the rest of the documentation. For now, please read along so you can have a high-level understanding of what Vue offers. :::tip Prerequisites The rest of the documentation assumes basic familiarity with HTML, CSS, and JavaScript. If you are totally new to frontend development, it might not be the best idea to jump right into a framework as your first step - grasp the basics and then come back! You can check your knowledge level with these overviews for [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript), [HTML](https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML) and [CSS](https://developer.mozilla.org/en-US/docs/Learn/CSS/First_steps) if needed. Prior experience with other frameworks helps, but is not required. ::: ## The Progressive Framework {#the-progressive-framework} Vue is a framework and ecosystem that covers most of the common features needed in frontend development. But the web is extremely diverse - the things we build on the web may vary drastically in form and scale. With that in mind, Vue is designed to be flexible and incrementally adoptable. Depending on your use case, Vue can be used in different ways: * Enhancing static HTML without a build step * Embedding as Web Components on any page * Single-Page Application (SPA) * Fullstack / Server-Side Rendering (SSR) * Jamstack / Static Site Generation (SSG) * Targeting desktop, mobile, WebGL, and even the terminal If you find these concepts intimidating, don't worry! The tutorial and guide only require basic HTML and JavaScript knowledge, and you should be able to follow along without being an expert in any of these. If you are an experienced developer interested in how to best integrate Vue into your stack, or you are curious about what these terms mean, we discuss them in more detail in [Ways of Using Vue](/guide/extras/ways-of-using-vue). Despite the flexibility, the core knowledge about how Vue works is shared across all these use cases. Even if you are just a beginner now, the knowledge gained along the way will stay useful as you grow to tackle more ambitious goals in the future. If you are a veteran, you can pick the optimal way to leverage Vue based on the problems you are trying to solve, while retaining the same productivity. This is why we call Vue "The Progressive Framework": it's a framework that can grow with you and adapt to your needs. ## Single-File Components {#single-file-components} In most build-tool-enabled Vue projects, we author Vue components using an HTML-like file format called **Single-File Component** (also known as `*.vue` files, abbreviated as **SFC**). A Vue SFC, as the name suggests, encapsulates the component's logic (JavaScript), template (HTML), and styles (CSS) in a single file. Here's the previous example, written in SFC format: ```vue ``` ```vue ``` SFC is a defining feature of Vue and is the recommended way to author Vue components **if** your use case warrants a build setup. You can learn more about the [how and why of SFC](/guide/scaling-up/sfc) in its dedicated section - but for now, just know that Vue will handle all the build tools setup for you. ## API Styles {#api-styles} Vue components can be authored in two different API styles: **Options API** and **Composition API**. ### Options API {#options-api} With Options API, we define a component's logic using an object of options such as `data`, `methods`, and `mounted`. Properties defined by options are exposed on `this` inside functions, which points to the component instance: ```vue ``` [Try it in the Playground](https://play.vuejs.org/#eNptkMFqxCAQhl9lkB522ZL0HNKlpa/Qo4e1ZpLIGhUdl5bgu9es2eSyIMio833zO7NP56pbRNawNkivHJ25wV9nPUGHvYiaYOYGoK7Bo5CkbgiBBOFy2AkSh2N5APmeojePCkDaaKiBt1KnZUuv3Ky0PppMsyYAjYJgigu0oEGYDsirYUAP0WULhqVrQhptF5qHQhnpcUJD+wyQaSpUd/Xp9NysVY/yT2qE0dprIS/vsds5Mg9mNVbaDofL94jZpUgJXUKBCvAy76ZUXY53CTd5tfX2k7kgnJzOCXIF0P5EImvgQ2olr++cbRE4O3+t6JxvXj0ptXVpye1tvbFY+ge/NJZt) ### Composition API {#composition-api} With Composition API, we define a component's logic using imported API functions. In SFCs, Composition API is typically used with [` ``` [Try it in the Playground](https://play.vuejs.org/#eNpNkMFqwzAQRH9lMYU4pNg9Bye09NxbjzrEVda2iLwS0spQjP69a+yYHnRYad7MaOfiw/tqSliciybqYDxDRE7+qsiM3gWGGQJ2r+DoyyVivEOGLrgRDkIdFCmqa1G0ms2EELllVKQdRQa9AHBZ+PLtuEm7RCKVd+ChZRjTQqwctHQHDqbvMUDyd7mKip4AGNIBRyQujzArgtW/mlqb8HRSlLcEazrUv9oiDM49xGGvXgp5uT5his5iZV1f3r4HFHvDprVbaxPhZf4XkKub/CDLaep1T7IhGRhHb6WoTADNT2KWpu/aGv24qGKvrIrr5+Z7hnneQnJu6hURvKl3ryL/ARrVkuI=) ### Which to Choose? {#which-to-choose} Both API styles are fully capable of covering common use cases. They are different interfaces powered by the exact same underlying system. In fact, the Options API is implemented on top of the Composition API! The fundamental concepts and knowledge about Vue are shared across the two styles. The Options API is centered around the concept of a "component instance" (`this` as seen in the example), which typically aligns better with a class-based mental model for users coming from OOP language backgrounds. It is also more beginner-friendly by abstracting away the reactivity details and enforcing code organization via option groups. The Composition API is centered around declaring reactive state variables directly in a function scope and composing state from multiple functions together to handle complexity. It is more free-form and requires an understanding of how reactivity works in Vue to be used effectively. In return, its flexibility enables more powerful patterns for organizing and reusing logic. You can learn more about the comparison between the two styles and the potential benefits of Composition API in the [Composition API FAQ](/guide/extras/composition-api-faq). If you are new to Vue, here's our general recommendation: * For learning purposes, go with the style that looks easier to understand to you. Again, most of the core concepts are shared between the two styles. You can always pick up the other style later. * For production use: * Go with Options API if you are not using build tools, or plan to use Vue primarily in low-complexity scenarios, e.g. progressive enhancement. * Go with Composition API + Single-File Components if you plan to build full applications with Vue. You don't have to commit to only one style during the learning phase. The rest of the documentation will provide code samples in both styles where applicable, and you can toggle between them at any time using the **API Preference switches** at the top of the left sidebar. ## Still Got Questions? {#still-got-questions} Check out our [FAQ](/about/faq). ## Pick Your Learning Path {#pick-your-learning-path} Different developers have different learning styles. Feel free to pick a learning path that suits your preference - although we do recommend going over all of the content, if possible! --- --- url: /guide/quick-start.md --- # Quick Start {#quick-start} ## Try Vue Online {#try-vue-online} * To quickly get a taste of Vue, you can try it directly in our [Playground](https://play.vuejs.org/#eNo9jcEKwjAMhl/lt5fpQYfXUQfefAMvvRQbddC1pUuHUPrudg4HIcmXjyRZXEM4zYlEJ+T0iEPgXjn6BB8Zhp46WUZWDjCa9f6w9kAkTtH9CRinV4fmRtZ63H20Ztesqiylphqy3R5UYBqD1UyVAPk+9zkvV1CKbCv9poMLiTEfR2/IXpSoXomqZLtti/IFwVtA9A==). * If you prefer a plain HTML setup without any build steps, you can use this [JSFiddle](https://jsfiddle.net/yyx990803/2ke1ab0z/) as your starting point. * If you are already familiar with Node.js and the concept of build tools, you can also try a complete build setup right within your browser on [StackBlitz](https://vite.new/vue). * To get a walkthrough of the recommended setup, watch this interactive [Scrimba](http://scrimba.com/links/vue-quickstart) tutorial that shows you how to run, edit, and deploy your first Vue app. ## Creating a Vue Application {#creating-a-vue-application} :::tip Prerequisites * Familiarity with the command line * Install [Node.js](https://nodejs.org/) version `^22.18.0 || >=24.12.0` ::: In this section we will introduce how to scaffold a Vue [Single Page Application](/guide/extras/ways-of-using-vue#single-page-application-spa) on your local machine. The created project will be using a build setup based on [Vite](https://vite.dev/) and allow us to use Vue [Single-File Components](/guide/scaling-up/sfc) (SFCs). Make sure you have an up-to-date version of [Node.js](https://nodejs.org/) installed and your current working directory is the one where you intend to create a project. Run the following command in your command line (without the `$` sign): ::: code-group ```sh [npm] $ npm create vue@latest ``` ```sh [pnpm] $ pnpm create vue@latest ``` ```sh [yarn] # For Yarn (v1+) $ yarn create vue # For Yarn Modern (v2+) $ yarn create vue@latest # For Yarn ^v4.11 $ yarn dlx create-vue@latest ``` ```sh [bun] $ bun create vue@latest ``` ::: This command will install and execute [create-vue](https://github.com/vuejs/create-vue), the official Vue project scaffolding tool. You will be presented with prompts for several optional features such as TypeScript and testing support: If you are unsure about an option, simply choose `No` by hitting enter for now. Once the project is created, follow the instructions to install dependencies and start the dev server: ::: code-group ```sh-vue [npm] $ cd {{''}} $ npm install $ npm run dev ``` ```sh-vue [pnpm] $ cd {{''}} $ pnpm install $ pnpm run dev ``` ```sh-vue [yarn] $ cd {{''}} $ yarn $ yarn dev ``` ```sh-vue [bun] $ cd {{''}} $ bun install $ bun run dev ``` ::: You should now have your first Vue project running! Note that the example components in the generated project are written using the [Composition API](/guide/introduction#composition-api) and ` ``` Here we are using [unpkg](https://unpkg.com/), but you can also use any CDN that serves npm packages, for example [jsdelivr](https://www.jsdelivr.com/package/npm/vue) or [cdnjs](https://cdnjs.com/libraries/vue). Of course, you can also download this file and serve it yourself. When using Vue from a CDN, there is no "build step" involved. This makes the setup a lot simpler, and is suitable for enhancing static HTML or integrating with a backend framework. However, you won't be able to use the Single-File Component (SFC) syntax. ### Using the Global Build {#using-the-global-build} The above link loads the *global build* of Vue, where all top-level APIs are exposed as properties on the global `Vue` object. Here is a full example using the global build: ```html
{{ message }}
``` [CodePen Demo >](https://codepen.io/vuejs-examples/pen/QWJwJLp) ```html
{{ message }}
``` [CodePen Demo >](https://codepen.io/vuejs-examples/pen/eYQpQEG) :::tip Many of the examples for Composition API throughout the guide will be using the ` ``` ```html{3,4}
{{ message }}
``` Notice that we are using `
{{ message }}
``` [CodePen Demo >](https://codepen.io/vuejs-examples/pen/wvQKQyM) ```html{1-7,12}
{{ message }}
``` [CodePen Demo >](https://codepen.io/vuejs-examples/pen/YzRyRYM) You can also add entries for other dependencies to the import map - but make sure they point to the ES modules version of the library you intend to use. :::tip Import Maps Browser Support Import Maps is a relatively new browser feature. Make sure to use a browser within its [support range](https://caniuse.com/import-maps). In particular, it is only supported in Safari 16.4+. ::: :::warning Notes on Production Use The examples so far are using the development build of Vue - if you intend to use Vue from a CDN in production, make sure to check out the [Production Deployment Guide](/guide/best-practices/production-deployment#without-build-tools). While it is possible to use Vue without a build system, an alternative approach to consider is using [`vuejs/petite-vue`](https://github.com/vuejs/petite-vue) that could better suit the context where [`jquery/jquery`](https://github.com/jquery/jquery) (in the past) or [`alpinejs/alpine`](https://github.com/alpinejs/alpine) (in the present) might be used instead. ::: ### Splitting Up the Modules {#splitting-up-the-modules} As we dive deeper into the guide, we may need to split our code into separate JavaScript files so that they are easier to manage. For example: ```html [index.html]
``` ```js [my-component.js] export default { data() { return { count: 0 } }, template: `
Count is: {{ count }}
` } ``` ```js [my-component.js] import { ref } from 'vue' export default { setup() { const count = ref(0) return { count } }, template: `
Count is: {{ count }}
` } ``` If you directly open the above `index.html` in your browser, you will find that it throws an error because ES modules cannot work over the `file://` protocol, which is the protocol the browser uses when you open a local file. Due to security reasons, ES modules can only work over the `http://` protocol, which is what the browsers use when opening pages on the web. In order for ES modules to work on our local machine, we need to serve the `index.html` over the `http://` protocol, with a local HTTP server. To start a local HTTP server, first make sure you have [Node.js](https://nodejs.org/en/) installed, then run `npx serve` from the command line in the same directory where your HTML file is. You can also use any other HTTP server that can serve static files with the correct MIME types. You may have noticed that the imported component's template is inlined as a JavaScript string. If you are using VS Code, you can install the [es6-string-html](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html) extension and prefix the strings with a `/*html*/` comment to get syntax highlighting for them. ## Frameworks {#frameworks} There are Vue frameworks which support [SSR](/guide/scaling-up/ssr) and other features out-of-the-box: * [Nuxt](https://nuxt.com/) * [Vike](https://vike.dev/) * [Astro](https://astro.build/) * [Quasar](https://quasar.dev/) :::tip The general recommendation is to use a framework only if you need SSR. If you don't need SSR, you can simply use [Vite](https://vite.dev/) (this is what the section above [Creating a Vue Application](#creating-a-vue-application) scaffolds). ::: :::info Vue frameworks typically use Vite under the hood, so directly using Vite instead of a Vue framework is a simpler setup if you don't need SSR. That said, frameworks also support extra features, such as UI themes, which can also be a reason to favor a Vue framework instead of just using Vite. ::: ## Next Steps {#next-steps} If you skipped the [Introduction](/guide/introduction), we strongly recommend reading it before moving on to the rest of the documentation. --- --- url: /guide/essentials/application.md --- # Creating a Vue Application {#creating-a-vue-application} ## The Application Instance {#the-application-instance} Every Vue application starts by creating a new **application instance** with the [`createApp`](/api/application#createapp) function: ```js import { createApp } from 'vue' const app = createApp({ /* root component options */ }) ``` ## The Root Component {#the-root-component} The object we are passing into `createApp` is in fact a component. Every app requires a "root component" that can contain other components as its children. If you are using Single-File Components, we typically import the root component from another file: ```js import { createApp } from 'vue' // import the root component App from a single-file component. import App from './App.vue' const app = createApp(App) ``` While many examples in this guide only need a single component, most real applications are organized into a tree of nested, reusable components. For example, a Todo application's component tree might look like this: ``` App (root component) ├─ TodoList │ └─ TodoItem │ ├─ TodoDeleteButton │ └─ TodoEditButton └─ TodoFooter ├─ TodoClearButton └─ TodoStatistics ``` In later sections of the guide, we will discuss how to define and compose multiple components together. Before that, we will focus on what happens inside a single component. ## Mounting the App {#mounting-the-app} An application instance won't render anything until its `.mount()` method is called. It expects a "container" argument, which can either be an actual DOM element or a selector string: ```html
``` ```js app.mount('#app') ``` The content of the app's root component will be rendered inside the container element. The container element itself is not considered part of the app. The `.mount()` method should always be called after all app configurations and asset registrations are done. Also note that its return value, unlike the asset registration methods, is the root component instance instead of the application instance. ### In-DOM Root Component Template {#in-dom-root-component-template} The template for the root component is usually part of the component itself, but it is also possible to provide the template separately by writing it directly inside the mount container: ```html
``` ```js import { createApp } from 'vue' const app = createApp({ data() { return { count: 0 } } }) app.mount('#app') ``` Vue will automatically use the container's `innerHTML` as the template if the root component does not already have a `template` option. In-DOM templates are often used in applications that are [using Vue without a build step](/guide/quick-start.html#using-vue-from-cdn). They can also be used in conjunction with server-side frameworks, where the root template might be generated dynamically by the server. ## App Configurations {#app-configurations} The application instance exposes a `.config` object that allows us to configure a few app-level options, for example, defining an app-level error handler that captures errors from all descendant components: ```js app.config.errorHandler = (err) => { /* handle error */ } ``` The application instance also provides a few methods for registering app-scoped assets. For example, registering a component: ```js app.component('TodoDeleteButton', TodoDeleteButton) ``` This makes the `TodoDeleteButton` available for use anywhere in our app. We will discuss registration for components and other types of assets in later sections of the guide. You can also browse the full list of application instance APIs in its [API reference](/api/application). Make sure to apply all app configurations before mounting the app! ## Multiple Application Instances {#multiple-application-instances} You are not limited to a single application instance on the same page. The `createApp` API allows multiple Vue applications to co-exist on the same page, each with its own scope for configuration and global assets: ```js const app1 = createApp({ /* ... */ }) app1.mount('#container-1') const app2 = createApp({ /* ... */ }) app2.mount('#container-2') ``` If you are using Vue to enhance server-rendered HTML and only need Vue to control specific parts of a large page, avoid mounting a single Vue application instance on the entire page. Instead, create multiple small application instances and mount them on the elements they are responsible for. --- --- url: /guide/essentials/template-syntax.md --- # Template Syntax {#template-syntax} Vue uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying component instance's data. All Vue templates are syntactically valid HTML that can be parsed by spec-compliant browsers and HTML parsers. Under the hood, Vue compiles the templates into highly-optimized JavaScript code. Combined with the reactivity system, Vue can 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](/guide/extras/render-function) instead of templates, with optional JSX support. However, do note that they do not enjoy the same level of compile-time optimizations as templates. ## Text Interpolation {#text-interpolation} The most basic form of data binding is text interpolation using the "Mustache" syntax (double curly braces): ```vue-html Message: {{ msg }} ``` The mustache tag will be replaced with the value of the `msg` property [from the corresponding component instance](/guide/essentials/reactivity-fundamentals#declaring-reactive-state). It will also be updated whenever the `msg` property changes. ## Raw HTML {#raw-html} The double mustaches interpret the data as plain text, not HTML. In order to output real HTML, you will need to use the [`v-html` directive](/api/built-in-directives#v-html): ```vue-html

Using text interpolation: {{ rawHtml }}

Using v-html directive:

``` Here we're encountering something new. The `v-html` 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're basically saying "keep this element's inner HTML up-to-date with the `rawHtml` property on the current active instance." 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. :::warning Security Warning Dynamically rendering arbitrary HTML on your website can be very dangerous because it can easily lead to [XSS vulnerabilities](https://en.wikipedia.org/wiki/Cross-site_scripting). Only use `v-html` on trusted content and **never** on user-provided content. ::: ## Attribute Bindings {#attribute-bindings} Mustaches cannot be used inside HTML attributes. Instead, use a [`v-bind` directive](/api/built-in-directives#v-bind): ```vue-html
``` The `v-bind` directive instructs Vue to keep the element's `id` attribute in sync with the component's `dynamicId` property. If the bound value is `null` or `undefined`, then the attribute will be removed from the rendered element. ### Shorthand {#shorthand} Because `v-bind` is so commonly used, it has a dedicated shorthand syntax: ```vue-html
``` Attributes that start with `:` may look a bit different from normal HTML, but it is in fact a valid character 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 optional, but you will likely appreciate it when you learn more about its usage later. > For the rest of the guide, we will be using the shorthand syntax in code examples, as that's the most common usage for Vue developers. ### Same-name Shorthand {#same-name-shorthand} * Only supported in 3.4+ If the attribute has the same name as the variable name of the JavaScript value being bound, the syntax can be further shortened to omit the attribute value: ```vue-html
``` This is similar to the property shorthand syntax when declaring objects in JavaScript. Note this is a feature that is only available in Vue 3.4 and above. ### Boolean Attributes {#boolean-attributes} [Boolean attributes](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#boolean-attributes) are attributes that can indicate true / false values by their presence on an element. For example, [`disabled`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled) is one of the most commonly used boolean attributes. `v-bind` works a bit differently in this case: ```vue-html ``` The `disabled` attribute will be included if `isButtonDisabled` has a [truthy value](https://developer.mozilla.org/en-US/docs/Glossary/Truthy). It will also be included if the value is an empty string, maintaining consistency with ` ``` For more complex logic, we can declare functions that mutate refs in the same scope and expose them as methods alongside the state: ```js{7-10,15} import { ref } from 'vue' export default { setup() { const count = ref(0) function increment() { // .value is needed in JavaScript count.value++ } // don't forget to expose the function as well. return { count, increment } } } ``` Exposed methods can then be used as event handlers: ```vue-html{1} ``` Here's the example live on [Codepen](https://codepen.io/vuejs-examples/pen/WNYbaqo), without using any build tools. ### ` ``` [Try it in the Playground](https://play.vuejs.org/#eNo9jUEKgzAQRa8yZKMiaNcllvYe2dgwQqiZhDhxE3L3jrW4/DPvv1/UK8Zhz6juSm82uciwIef4MOR8DImhQMIFKiwpeGgEbQwZsoE2BhsyMUwH0d66475ksuwCgSOb0CNx20ExBCc77POase8NVUN6PBdlSwKjj+vMKAlAvzOzWJ52dfYzGXXpjPoBAKX856uopDGeFfnq8XKp+gWq4FAi) Top-level imports, variables and functions declared in ` ``` [Try it in the Playground](https://play.vuejs.org/#eNp1kE9Lw0AQxb/KI5dtoTainkoaaREUoZ5EEONhm0ybYLO77J9CCfnuzta0vdjbzr6Zeb95XbIwZroPlMySzJW2MR6OfDB5oZrWaOvRwZIsfbOnCUrdmuCpQo+N1S0ET4pCFarUynnI4GttMT9PjLpCAUq2NIN41bXCkyYxiZ9rrX/cDF/xDYiPQLjDDRbVXqqSHZ5DUw2tg3zP8lK6pvxHe2DtvSasDs6TPTAT8F2ofhzh0hTygm5pc+I1Yb1rXE3VMsKsyDm5JcY/9Y5GY8xzHI+wnIpVw4nTI/10R2rra+S4xSPEJzkBvvNNs310ztK/RDlLLjy1Zic9cQVkJn+R7gIwxJGlMXiWnZEq77orhH3Pq2NH9DjvTfpfSBSbmA==) Here we have declared a computed property `publishedBooksMessage`. The `computed()` function expects to be passed a [getter function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#description), and the returned value is a **computed ref**. Similar to normal refs, you can access the computed result as `publishedBooksMessage.value`. Computed refs are also auto-unwrapped in templates so you can reference them without `.value` in template expressions. A computed property automatically tracks its reactive dependencies. Vue is aware that the computation of `publishedBooksMessage` depends on `author.books`, so it will update any bindings that depend on `publishedBooksMessage` when `author.books` changes. See also: [Typing Computed](/guide/typescript/composition-api#typing-computed) ## Computed Caching vs. Methods {#computed-caching-vs-methods} You may have noticed we can achieve the same result by invoking a method in the expression: ```vue-html

{{ calculateBooksMessage() }}

``` ```js // in component methods: { calculateBooksMessage() { return this.author.books.length > 0 ? 'Yes' : 'No' } } ``` ```js // in component function calculateBooksMessage() { return author.books.length > 0 ? 'Yes' : 'No' } ``` Instead of a computed property, we can define the same function as a method. For the end result, the two approaches are indeed exactly the same. However, the difference is that **computed properties are cached based on their reactive dependencies.** A computed property will only re-evaluate when some of its reactive dependencies have changed. This means as long as `author.books` has not changed, multiple access to `publishedBooksMessage` will immediately return the previously computed result without having to run the getter function again. This also means the following computed property will never update, because `Date.now()` is not a reactive dependency: ```js computed: { now() { return Date.now() } } ``` ```js const now = computed(() => Date.now()) ``` In comparison, a method invocation will **always** run the function whenever a re-render happens. Why do we need caching? Imagine we have an expensive computed property `list`, which requires looping through a huge array and doing a lot of computations. Then we may have other computed properties that in turn depend on `list`. Without caching, we would be executing `list`’s getter many more times than necessary! In cases where you do not want caching, use a method call instead. ## Writable Computed {#writable-computed} Computed properties are by default getter-only. If you attempt to assign a new value to a computed property, you will receive a runtime warning. In the rare cases where you need a "writable" computed property, you can create one by providing both a getter and a setter: ```js export default { data() { return { firstName: 'John', lastName: 'Doe' } }, computed: { fullName: { // getter get() { return this.firstName + ' ' + this.lastName }, // setter set(newValue) { // Note: we are using destructuring assignment syntax here. [this.firstName, this.lastName] = newValue.split(' ') } } } } ``` Now when you run `this.fullName = 'John Doe'`, the setter will be invoked and `this.firstName` and `this.lastName` will be updated accordingly. ```vue ``` Now when you run `fullName.value = 'John Doe'`, the setter will be invoked and `firstName` and `lastName` will be updated accordingly. ## Getting the Previous Value {#previous} * Only supported in 3.4+ ```js export default { data() { return { count: 2 } }, computed: { // This computed will return the value of count when it's less or equal to 3. // When count is >=4, the last value that fulfilled our condition will be returned // instead until count is less or equal to 3 alwaysSmall(_, previous) { if (this.count <= 3) { return this.count } return previous } } } ``` ```vue ``` In case you're using a writable computed: ```js export default { data() { return { count: 2 } }, computed: { alwaysSmall: { get(_, previous) { if (this.count <= 3) { return this.count } return previous; }, set(newValue) { this.count = newValue * 2 } } } } ``` ```vue ``` ## Best Practices {#best-practices} ### Getters should be side-effect free {#getters-should-be-side-effect-free} It is important to remember that computed getter functions should only perform pure computation and be free of side effects. For example, **don't mutate other state, make async requests, or mutate the DOM inside a computed getter!** Think of a computed property as declaratively describing how to derive a value based on other values - its only responsibility should be computing and returning that value. Later in the guide we will discuss how we can perform side effects in reaction to state changes with [watchers](./watchers). ### Avoid mutating computed value {#avoid-mutating-computed-value} The returned value from a computed property is derived state. Think of it as a temporary snapshot - every time the source state changes, a new snapshot is created. It does not make sense to mutate a snapshot, so a computed return value should be treated as read-only and never be mutated - instead, update the source state it depends on to trigger new computations. --- --- url: /guide/essentials/class-and-style.md --- # Class and Style Bindings {#class-and-style-bindings} A common need for data binding is manipulating an element's class list and inline styles. Since `class` and `style` are both attributes, we can use `v-bind` to assign them a string value dynamically, much like with other attributes. However, trying to generate those values using string concatenation can be annoying and error-prone. For this reason, Vue provides special enhancements when `v-bind` is used with `class` and `style`. In addition to strings, the expressions can also evaluate to objects or arrays. ## Binding HTML Classes {#binding-html-classes} ### Binding to Objects {#binding-to-objects} We can pass an object to `:class` (short for `v-bind:class`) to dynamically toggle classes: ```vue-html
``` The above syntax means the presence of the `active` class will be determined by the [truthiness](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) of the data property `isActive`. You can have multiple classes toggled by having more fields in the object. In addition, the `:class` directive can also co-exist with the plain `class` attribute. So given the following state: ```js const isActive = ref(true) const hasError = ref(false) ``` ```js data() { return { isActive: true, hasError: false } } ``` And the following template: ```vue-html
``` It will render: ```vue-html
``` When `isActive` or `hasError` changes, the class list will be updated accordingly. For example, if `hasError` becomes `true`, the class list will become `"static active text-danger"`. The bound object doesn't have to be inline: ```js const classObject = reactive({ active: true, 'text-danger': false }) ``` ```js data() { return { classObject: { active: true, 'text-danger': false } } } ``` ```vue-html
``` This will render: ```vue-html
``` We can also bind to a [computed property](./computed) that returns an object. This is a common and powerful pattern: ```js const isActive = ref(true) const error = ref(null) const classObject = computed(() => ({ active: isActive.value && !error.value, 'text-danger': error.value && error.value.type === 'fatal' })) ``` ```js data() { return { isActive: true, error: null } }, computed: { classObject() { return { active: this.isActive && !this.error, 'text-danger': this.error && this.error.type === 'fatal' } } } ``` ```vue-html
``` ### Binding to Arrays {#binding-to-arrays} We can bind `:class` to an array to apply a list of classes: ```js const activeClass = ref('active') const errorClass = ref('text-danger') ``` ```js data() { return { activeClass: 'active', errorClass: 'text-danger' } } ``` ```vue-html
``` Which will render: ```vue-html
``` If you would like to also toggle a class in the list conditionally, you can do it with a ternary expression: ```vue-html
``` This will always apply `errorClass`, but `activeClass` will only be applied when `isActive` is truthy. However, this can be a bit verbose if you have multiple conditional classes. That's why it's also possible to use the object syntax inside the array syntax: ```vue-html
``` ### With Components {#with-components} > This section assumes knowledge of [Components](/guide/essentials/component-basics). Feel free to skip it and come back later. When you use the `class` attribute on a component with a single root element, those classes will be added to the component's root element and merged with any existing class already on it. For example, if we have a component named `MyComponent` with the following template: ```vue-html

Hi!

``` Then add some classes when using it: ```vue-html ``` The rendered HTML will be: ```vue-html

Hi!

``` The same is true for class bindings: ```vue-html ``` When `isActive` is truthy, the rendered HTML will be: ```vue-html

Hi!

``` If your component has multiple root elements, you would need to define which element will receive this class. You can do this using the `$attrs` component property: ```vue-html

Hi!

This is a child component ``` ```vue-html ``` Will render: ```html

Hi!

This is a child component ``` You can learn more about component attribute inheritance in [Fallthrough Attributes](/guide/components/attrs) section. ## Binding Inline Styles {#binding-inline-styles} ### Binding to Objects {#binding-to-objects-1} `:style` supports binding to JavaScript object values - it corresponds to an [HTML element's `style` property](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style): ```js const activeColor = ref('red') const fontSize = ref(30) ``` ```js data() { return { activeColor: 'red', fontSize: 30 } } ``` ```vue-html
``` Although camelCase keys are recommended, `:style` also supports kebab-cased CSS property keys (corresponds to how they are used in actual CSS) - for example: ```vue-html
``` It is often a good idea to bind to a style object directly so that the template is cleaner: ```js const styleObject = reactive({ color: 'red', fontSize: '30px' }) ``` ```js data() { return { styleObject: { color: 'red', fontSize: '13px' } } } ``` ```vue-html
``` Again, object style binding is often used in conjunction with computed properties that return objects. `:style` directives can also coexist with regular style attributes, just like `:class`. Template: ```vue-html

hello

``` It will render: ```vue-html

hello

``` ### Binding to Arrays {#binding-to-arrays-1} We can bind `:style` to an array of multiple style objects. These objects will be merged and applied to the same element: ```vue-html
``` ### Auto-prefixing {#auto-prefixing} When you use a CSS property that requires a [vendor prefix](https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix) in `:style`, Vue will automatically add the appropriate prefix. Vue does this by checking at runtime to see which style properties are supported in the current browser. If the browser doesn't support a particular property then various prefixed variants will be tested to try to find one that is supported. ### Multiple Values {#multiple-values} You can provide an array of multiple (prefixed) values to a style property, for example: ```vue-html
``` This will only render the last value in the array which the browser supports. In this example, it will render `display: flex` for browsers that support the unprefixed version of flexbox. --- --- url: /guide/essentials/conditional.md --- # Conditional Rendering {#conditional-rendering} ## `v-if` {#v-if} The directive `v-if` is used to conditionally render a block. The block will only be rendered if the directive's expression returns a truthy value. ```vue-html

Vue is awesome!

``` ## `v-else` {#v-else} You can use the `v-else` directive to indicate an "else block" for `v-if`: ```vue-html

Vue is awesome!

Oh no 😢

``` [Try it in the Playground](https://play.vuejs.org/#eNpFjkEOgjAQRa8ydIMulLA1hegJ3LnqBskAjdA27RQXhHu4M/GEHsEiKLv5mfdf/sBOxux7j+zAuCutNAQOyZtcKNkZbQkGsFjBCJXVHcQBjYUSqtTKERR3dLpDyCZmQ9bjViiezKKgCIGwM21BGBIAv3oireBYtrK8ZYKtgmg5BctJ13WLPJnhr0YQb1Lod7JaS4G8eATpfjMinjTphC8wtg7zcwNKw/v5eC1fnvwnsfEDwaha7w==) [Try it in the Playground](https://play.vuejs.org/#eNpFjj0OwjAMha9iMsEAFWuVVnACNqYsoXV/RJpEqVOQqt6DDYkTcgRSWoplWX7y56fXs6O1u84jixlvM1dbSoXGuzWOIMdCekXQCw2QS5LrzbQLckje6VEJglDyhq1pMAZyHidkGG9hhObRYh0EYWOVJAwKgF88kdFwyFSdXRPBZidIYDWvgqVkylIhjyb4ayOIV3votnXxfwrk2SPU7S/PikfVfsRnGFWL6akCbeD9fLzmK4+WSGz4AA5dYQY=) A `v-else` element must immediately follow a `v-if` or a `v-else-if` element - otherwise it will not be recognized. ## `v-else-if` {#v-else-if} The `v-else-if`, as the name suggests, serves as an "else if block" for `v-if`. It can also be chained multiple times: ```vue-html
A
B
C
Not A/B/C
``` Similar to `v-else`, a `v-else-if` element must immediately follow a `v-if` or a `v-else-if` element. ## `v-if` on `