+ New pages are added to the documentation all the time. This page might not be included in all of the translations yet.
+
Take me home.
@@ -13,17 +19,22 @@
@@ -519,7 +565,7 @@ export default {
```
-For more information about using CSS modules, see [Vue Loader - CSS Modules](https://vue-loader.vuejs.org/guide/css-modules.html).
+For more information about using CSS modules, see [SFC Style Features: `
+
+
+ This could be e.g. documentation for the component.
+
+```
+
+## Language Blocks
+
+### ``
+
+- Each `*.vue` file can contain at most one top-level `` block at a time.
+
+- Contents will be extracted and passed on to `@vue/compiler-dom`, pre-compiled into JavaScript render functions, and attached to the exported component as its `render` option.
+
+### `
+```
+
+`lang` can be applied to any block - for example we can use `
+```
+
+Note the intergration with pre-processors may differ based on the toolchain. Check out the respective documentations for examples:
+
+- [Vite](https://vitejs.dev/guide/features.html#css-pre-processors)
+- [Vue CLI](https://cli.vuejs.org/guide/css.html#pre-processors)
+- [webpack + vue-loader](https://vue-loader.vuejs.org/guide/pre-processors.html#using-pre-processors)
+
+## Src Imports
+
+If you prefer splitting up your `*.vue` components into multiple files, you can use the `src` attribute to import an external file for a language block:
+
+```vue
+
+
+
+```
+
+Beware that `src` imports follow the same path resolution rules as webpack module requests, which means:
+
+- Relative paths need to start with `./`
+- You can import resources from npm dependencies:
+
+```vue
+
+
+
+
+
hi
+
+```
+
+Into the following:
+
+```vue
+
+
+
+
hi
+
+```
+
+### Child Component Root Elements
+
+With `scoped`, the parent component's styles will not leak into child components. However, a child component's root node will be affected by both the parent's scoped CSS and the child's scoped CSS. This is by design so that the parent can style the child root element for layout purposes.
+
+### Deep Selectors
+
+If you want a selector in `scoped` styles to be "deep", i.e. affecting child components, you can use the `:deep()` pseudo-class:
+
+```vue
+
+```
+
+The above will be compiled into:
+
+```css
+.a[data-v-f3f3eg9] .b {
+ /* ... */
+}
+```
+
+:::tip
+DOM content created with `v-html` are not affected by scoped styles, but you can still style them using deep selectors.
+:::
+
+### Slotted Selectors
+
+By default, scoped styles do not affect contents rendered by ``, as they are considered to be owned by the parent component passing them in. To explicitly target slot content, use the `:slotted` pseudo-class:
+
+```vue
+
+```
+
+### Global Selectors
+
+If you want just one rule to apply globally, you can use the `:global` pseudo-class rather than creating another `
+```
+
+### Mixing Local and Global Styles
+
+You can also include both scoped and non-scoped styles in the same component:
+
+```vue
+
+
+
+```
+
+### Scoped Style Tips
+
+- **Scoped styles do not eliminate the need for classes**. Due to the way browsers render various CSS selectors, `p { color: red }` will be many times slower when scoped (i.e. when combined with an attribute selector). If you use classes or ids instead, such as in `.example { color: red }`, then you virtually eliminate that performance hit.
+
+- **Be careful with descendant selectors in recursive components!** For a CSS rule with the selector `.a .b`, if the element that matches `.a` contains a recursive child component, then all `.b` in that child component will be matched by the rule.
+
+## `
+```
+
+The resulting classes are hashed to avoid collision, achieving the same effect of scoping the CSS to the current component only.
+
+Refer to the [CSS Modules spec](https://github.com/css-modules/css-modules) for more details such as [global exceptions](https://github.com/css-modules/css-modules#exceptions) and [composition](https://github.com/css-modules/css-modules#composition).
+
+### Custom Inject Name
+
+You can customize the property key of the injected classes object by giving the `module` attribute a value:
+
+```vue
+
+
red
+
+
+
+```
+
+### Usage with Composition API
+
+The injected classes can be accessed in `setup()` and `
+
+
+```
+
+The syntax works with [`
+
+
+
hello
+
+
+
+```
+
+The actual value will be compiled into a hashed CSS custom property, so the CSS is still static. The custom property will be applied to the component's root element via inline styles and reactively updated if the source value changes.
diff --git a/src/api/sfc-tooling.md b/src/api/sfc-tooling.md
new file mode 100644
index 0000000000..bd5bdf7c72
--- /dev/null
+++ b/src/api/sfc-tooling.md
@@ -0,0 +1,96 @@
+# SFC Tooling
+
+## Online Playgrounds
+
+You don't need to install anything on your machine to try out Vue SFCs - there are many online playgrounds that allow you to do so right in the browser:
+
+- [Vue SFC Playground](https://sfc.vuejs.org) (official, deployed from latest commit)
+- [VueUse Playground](https://play.vueuse.org)
+- [Vue on CodeSandbox](https://codesandbox.io/s/vue-3)
+- [Vue on Repl.it](https://replit.com/@templates/VueJS-with-Vite)
+- [Vue on Codepen](https://codepen.io/pen/editor/vue)
+- [Vue on StackBlitz](https://stackblitz.com/fork/vue)
+- [Vue on Components.studio](https://components.studio/create/vue3)
+- [Vue on WebComponents.dev](https://webcomponents.dev/create/cevue)
+
+It is also recommended to use these online playgrounds to provide reproductions when reporting bugs.
+
+## Project Scaffolding
+
+### Vite
+
+[Vite](https://vitejs.dev/) is a lightweight and fast build tool with first-class Vue SFC support. It is created by Evan You, who is also the author of Vue itself! To get started with Vite + Vue, simply run:
+
+```sh
+npm init vite@latest
+```
+
+Then select the Vue template and follow the instructions.
+
+- To learn more about Vite, check out the [Vite docs](https://vitejs.dev/guide/).
+- To configure Vue-specific behavior in a Vite project, for example passing options to the Vue compiler, check out the docs for [@vitejs/plugin-vue](https://github.com/vitejs/vite/tree/main/packages/plugin-vue#readme).
+
+The [SFC Playground](https://sfc.vuejs.org/) also supports downloading the files as a Vite project.
+
+### Vue CLI
+
+[Vue CLI](https://cli.vuejs.org/) is the official webpack-based build tool for Vue projects. To get started with Vue CLI:
+
+```sh
+npm install -g @vue/cli
+vue create hello-vue
+```
+
+- To learn more about Vue CLI, check out [Vue CLI docs](https://cli.vuejs.org/guide/installation.html).
+
+### Vite or Vue CLI?
+
+We recommend starting new projects with Vite as it offers significantly better development experience in terms of dev server startup and HMR update performance ([details](https://vitejs.dev/guide/why.html)). Only go with Vue CLI if you rely on specific webpack features (e.g. Module Federation).
+
+If you are a [Rollup](https://rollupjs.org/) user, you can safely adopt Vite as it uses Rollup for production builds and supports a Rollup-compatible plugin system. [Even Rollup's maintainer recommends Vite as THE web development wrapper for Rollup](https://twitter.com/lukastaegert/status/1412119729431584774).
+
+## IDE Support
+
+The recommended IDE setup is [VSCode](https://code.visualstudio.com/) + the [Volar](https://github.com/johnsoncodehk/volar) extension. Volar provides syntax highlighting and advanced IntelliSense for template expressions, component props and even slots validation. We strongly recommend this setup if you want to get the best possible experience with Vue SFCs, especially if you are also using TypeScript.
+
+[WebStorm](https://www.jetbrains.com/webstorm/) also provides decent support for Vue SFCs. However, do note as of now its support for `
```
-While this seems like a convenience, it requires a custom syntax that breaks the assumption of expressions inside of curly braces being "just JavaScript," which has both learning and implementation costs.
+While this seems like a convenience, it requires a custom syntax that breaks the assumption of expressions inside curly braces being "just JavaScript," which has both learning and implementation costs.
## 3.x Update
diff --git a/src/guide/migration/global-api-treeshaking.md b/src/guide/migration/global-api-treeshaking.md
index d730cf71e6..502a272334 100644
--- a/src/guide/migration/global-api-treeshaking.md
+++ b/src/guide/migration/global-api-treeshaking.md
@@ -107,7 +107,7 @@ export function render() {
This essentially means the `Transition` component only gets imported when the application actually makes use of it. In other words, if the application doesn’t have any `` component, the code supporting this feature will not be present in the final bundle.
-With global tree-shaking, the user only “pay” for the features they actually use. Even better, knowing that optional features won't increase the bundle size for applications not using them, framework size has become much less a concern for additional core features in the future, if at all.
+With global tree-shaking, the users only “pay” for the features they actually use. Even better, knowing that optional features won't increase the bundle size for applications not using them, framework size has become much less a concern for additional core features in the future, if at all.
::: warning Important
The above only applies to the [ES Modules builds](/guide/installation.html#explanation-of-different-builds) for use with tree-shaking capable bundlers - the UMD build still includes all features and exposes everything on the Vue global variable (and the compiler will produce appropriate output to use APIs off the global instead of importing).
diff --git a/src/guide/migration/introduction.md b/src/guide/migration/introduction.md
index 04e502288f..d86c317795 100644
--- a/src/guide/migration/introduction.md
+++ b/src/guide/migration/introduction.md
@@ -29,7 +29,7 @@ If you want to quickly try out Vue 3 in a new project:
- Scaffold via [Vite](https://github.com/vitejs/vite):
```bash
- npm init @vitejs/app hello-vue3 # OR yarn create @vitejs/app hello-vue3
+ npm init vite hello-vue3 -- --template vue # OR yarn create vite hello-vue3 --template vue
```
- Scaffold via [vue-cli](https://cli.vuejs.org/):
@@ -53,8 +53,8 @@ Some of the new features to keep an eye on in Vue 3 include:
- [Fragments](/guide/migration/fragments.html)
- [Emits Component Option](/guide/component-custom-events.html)
- [`createRenderer` API from `@vue/runtime-core`](https://github.com/vuejs/vue-next/tree/master/packages/runtime-core) to create custom renderers
-- [SFC Composition API Syntax Sugar (`
```
@@ -141,6 +172,8 @@ watchEffect(
The `flush` option also accepts `'sync'`, which forces the effect to always trigger synchronously. This is however inefficient and should be rarely needed.
+In Vue >= 3.2.0, `watchPostEffect` and `watchSyncEffect` aliases can also be used to make the code intention more obvious.
+
### Watcher Debugging
The `onTrack` and `onTrigger` options can be used to debug a watcher's behavior.
@@ -201,15 +234,48 @@ watch(count, (count, prevCount) => {
A watcher can also watch multiple sources at the same time using an array:
```js
-const firstName = ref('');
-const lastName = ref('');
+const firstName = ref('')
+const lastName = ref('')
watch([firstName, lastName], (newValues, prevValues) => {
- console.log(newValues, prevValues);
+ console.log(newValues, prevValues)
})
-firstName.value = "John"; // logs: ["John",""] ["", ""]
-lastName.value = "Smith"; // logs: ["John", "Smith"] ["John", ""]
+firstName.value = 'John' // logs: ["John", ""] ["", ""]
+lastName.value = 'Smith' // logs: ["John", "Smith"] ["John", ""]
+```
+
+However, if you are changing both watched sources simultaneously in the same function, the watcher will be executed only once:
+
+```js{9-13}
+setup() {
+ const firstName = ref('')
+ const lastName = ref('')
+
+ watch([firstName, lastName], (newValues, prevValues) => {
+ console.log(newValues, prevValues)
+ })
+
+ const changeValues = () => {
+ firstName.value = 'John'
+ lastName.value = 'Smith'
+ // logs: ["John", "Smith"] ["", ""]
+ }
+
+ return { changeValues }
+}
+```
+
+Note that multiple synchronous changes will only trigger the watcher once.
+
+It is possible to force the watcher to trigger after every change by using the setting `flush: 'sync'`, though that isn't usually recommended. Alternatively, [nextTick](/api/global-api.html#nexttick) can be used to wait for the watcher to run before making further changes. e.g.:
+
+```js
+const changeValues = async () => {
+ firstName.value = 'John' // logs: ["John", ""] ["", ""]
+ await nextTick()
+ lastName.value = 'Smith' // logs: ["John", "Smith"] ["John", ""]
+}
```
### Watching Reactive Objects
@@ -222,8 +288,9 @@ const numbers = reactive([1, 2, 3, 4])
watch(
() => [...numbers],
(numbers, prevNumbers) => {
- console.log(numbers, prevNumbers);
- })
+ console.log(numbers, prevNumbers)
+ }
+)
numbers.push(5) // logs: [1,2,3,4,5] [1,2,3,4]
```
@@ -231,62 +298,51 @@ numbers.push(5) // logs: [1,2,3,4,5] [1,2,3,4]
Attempting to check for changes of properties in a deeply nested object or array will still require the `deep` option to be true:
```js
-const state = reactive({
- id: 1,
- attributes: {
- name: "",
- },
-});
+const state = reactive({
+ id: 1,
+ attributes: {
+ name: ''
+ }
+})
watch(
() => state,
(state, prevState) => {
- console.log(
- "not deep ",
- state.attributes.name,
- prevState.attributes.name
- );
+ console.log('not deep', state.attributes.name, prevState.attributes.name)
}
-);
+)
watch(
() => state,
(state, prevState) => {
- console.log(
- "deep ",
- state.attributes.name,
- prevState.attributes.name
- );
+ console.log('deep', state.attributes.name, prevState.attributes.name)
},
{ deep: true }
-);
+)
-state.attributes.name = "Alex"; // Logs: "deep " "Alex" "Alex"
+state.attributes.name = 'Alex' // Logs: "deep" "Alex" "Alex"
```
However, watching a reactive object or array will always return a reference to the current value of that object for both the current and previous value of the state. To fully watch deeply nested objects and arrays, a deep copy of values may be required. This can be achieved with a utility such as [lodash.cloneDeep](https://lodash.com/docs/4.17.15#cloneDeep)
```js
-import _ from 'lodash';
+import _ from 'lodash'
const state = reactive({
id: 1,
attributes: {
- name: "",
- },
-});
+ name: ''
+ }
+})
watch(
() => _.cloneDeep(state),
(state, prevState) => {
- console.log(
- state.attributes.name,
- prevState.attributes.name
- );
+ console.log(state.attributes.name, prevState.attributes.name)
}
-);
+)
-state.attributes.name = "Alex"; // Logs: "Alex" ""
+state.attributes.name = 'Alex' // Logs: "Alex" ""
```
### Shared Behavior with `watchEffect`
diff --git a/src/guide/reactivity-fundamentals.md b/src/guide/reactivity-fundamentals.md
index 49caf3256f..bbaef88a95 100644
--- a/src/guide/reactivity-fundamentals.md
+++ b/src/guide/reactivity-fundamentals.md
@@ -1,5 +1,7 @@
# Reactivity Fundamentals
+> This section uses [single-file component](single-file-component.html) syntax for code examples
+
## Declaring Reactive State
To create a reactive state from a JavaScript object, we can use a `reactive` method:
@@ -74,7 +76,7 @@ When a ref is returned as a property on the render context (the object returned
```
:::tip
-If you don't need to access the actual object instance, you can wrap it in a `reactive`:
+If you don't want to access the actual object instance, you can wrap it in a `reactive`:
```js
nested: reactive({
diff --git a/src/guide/render-function.md b/src/guide/render-function.md
index fda002f2e2..902f229421 100644
--- a/src/guide/render-function.md
+++ b/src/guide/render-function.md
@@ -350,7 +350,7 @@ render() {
#### Event Modifiers
-For the `.passive`, `.capture`, and `.once` event modifiers, they can be concatenated after the event name using camel case.
+For the `.passive`, `.capture`, and `.once` event modifiers, they can be concatenated after the event name using camelCase.
For example:
diff --git a/src/guide/single-file-component.md b/src/guide/single-file-component.md
index df5927be3a..595fc444a4 100644
--- a/src/guide/single-file-component.md
+++ b/src/guide/single-file-component.md
@@ -1,174 +1,88 @@
# Single File Components
-## Introduction
-
-In many Vue projects, global components will be defined using `app.component()`, followed by `app.mount('#app')` to target a container element in the body of every page.
-
-This can work very well for small to medium-sized projects, where JavaScript is only used to enhance certain views. In more complex projects however, or when your frontend is entirely driven by JavaScript, these disadvantages become apparent:
-
-- **Global definitions** force unique names for every component
-- **String templates** lack syntax highlighting and require ugly slashes for multiline HTML
-- **No CSS support** means that while HTML and JavaScript are modularized into components, CSS is conspicuously left out
-- **No build step** restricts us to HTML and ES5 JavaScript, rather than preprocessors like Pug (formerly Jade) and Babel
-
-All of these are solved by **single-file components** with a `.vue` extension, made possible with build tools such as Webpack or Browserify.
-
-Here's an example of a file we'll call `Hello.vue`:
-
-
-
-Now we get:
-
-- [Complete syntax highlighting](https://github.com/vuejs/awesome-vue#source-code-editing)
-- [CommonJS modules](https://webpack.js.org/concepts/modules/#what-is-a-webpack-module)
-- [Component-scoped CSS](https://vue-loader.vuejs.org/en/features/scoped-css.html)
-
-As promised, we can also use preprocessors such as Pug, Babel (with ES2015 modules), and Stylus for cleaner and more feature-rich components.
-
-
+Learn about single file components with a free video lesson on Vue School
-These specific languages are only examples. You could as easily use TypeScript, SCSS, PostCSS, or whatever other preprocessors that help you be productive. If using Webpack with `vue-loader`, it also has first-class support for CSS Modules.
-
-### What About Separation of Concerns?
+## Introduction
-One important thing to note is that **separation of concerns is not equal to separation of file types.** In modern UI development, we have found that instead of dividing the codebase into three huge layers that interweave with one another, it makes much more sense to divide them into loosely-coupled components and compose them. Inside a component, its template, logic and styles are inherently coupled, and collocating them actually makes the component more cohesive and maintainable.
+Vue Single File Components (aka `*.vue` files, abbreviated as **SFC**) is a special file format that allows us to encapsulate the template, logic, **and** styling of a Vue component in a single file. Here's an example SFC:
-Even if you don't like the idea of Single-File Components, you can still leverage its hot-reloading and pre-compilation features by separating your JavaScript and CSS into separate files:
+```vue
+
-```html
-
-
This will be pre-compiled
+
{{ greeting }}
-
-
-```
-
-## Getting Started
-
-### Example Sandbox
-
-If you want to dive right in and start playing with single-file components, check out [this simple todo app](https://codesandbox.io/s/vue-todo-list-app-with-single-file-component-vzkl3?file=/src/App.vue) on CodeSandbox.
-
-### For Users New to Module Build Systems in JavaScript
-With `.vue` components, we're entering the realm of advanced JavaScript applications. That means learning to use a few additional tools if you haven't already:
-
-- **Node Package Manager (npm)**: Read the [Getting Started guide](https://docs.npmjs.com/packages-and-modules/getting-packages-from-the-registry) section about how to get packages from the registry.
-
-- **Modern JavaScript with ES2015/16**: Read through Babel's [Learn ES2015 guide](https://babeljs.io/docs/en/learn). You don't have to memorize every feature right now, but keep this page as a reference you can come back to.
-
-After you've taken a day to dive into these resources, we recommend checking out [Vue CLI](https://cli.vuejs.org/). Follow the instructions and you should have a Vue project with `.vue` components, ES2015, webpack and hot-reloading in no time!
-
-### For Advanced Users
-
-The CLI takes care of most of the tooling configurations for you, but also allows fine-grained customization through its own [config options](https://cli.vuejs.org/config/).
-
-In case you prefer setting up your own build setup from scratch, you will need to manually configure webpack with [vue-loader](https://vue-loader.vuejs.org). To learn more about webpack itself, check out [their official docs](https://webpack.js.org/configuration/) and [webpack learning academy](https://webpack.academy/p/the-core-concepts).
-
-### Building with rollup
-
-Most of the time when developing a third-party library we want to build it in a way that allows the consumers of the library to [tree shake](https://webpack.js.org/guides/tree-shaking/) it. To enable tree-shaking we need to build `esm` modules. Since webpack and, in turn, vue-cli do not support building `esm` modules we need to rely on [rollup](https://rollupjs.org/).
-
-#### Installing Rollup
-
-We will need to install Rollup and a few dependencies:
-
-```bash
-npm install --save-dev rollup @rollup/plugin-commonjs rollup-plugin-vue
+
```
-These are the minimal amount of rollup plugins that we need to use to compile the code in an `esm` module. We may want to also add [rollup-plugin-babel](https://github.com/rollup/plugins/tree/master/packages/babel) to transpile their code and [node-resolve](https://github.com/rollup/plugins/tree/master/packages/node-resolve) if we use dependencies that we want to bundle with our library.
+As we can see, Vue SFC is a natural extension of the classic trio of HTML, CSS and JavaScript. Each `*.vue` file consists of three types of top-level language blocks: ``, `
```
### `entry-client.js`
-The client entry creates the application using the root component factory and mounts it to the DOM:
+The client entry creates the application using the `App.vue` component and mounts it to the DOM:
```js
-import createApp from './app'
+import { createSSRApp } from 'vue'
+import App from './App.vue'
// client-specific bootstrapping logic...
-const { app } = createApp({
- // here we can pass additional arguments to app factory
-})
+const app = createSSRApp(App)
// this assumes App.vue template root element has `id="app"`
app.mount('#app')
@@ -122,12 +143,11 @@ app.mount('#app')
The server entry uses a default export which is a function that can be called repeatedly for each render. At this moment, it doesn't do much other than returning the app instance - but later we will perform server-side route matching and data pre-fetching logic here.
```js
-import createApp from './app'
+import { createSSRApp } from 'vue'
+import App from './App.vue'
-export default function() {
- const { app } = createApp({
- /*...*/
- })
+export default function () {
+ const app = createSSRApp(App)
return {
app
diff --git a/src/guide/template-syntax.md b/src/guide/template-syntax.md
index 9b2c55a555..bcb024e00b 100644
--- a/src/guide/template-syntax.md
+++ b/src/guide/template-syntax.md
@@ -26,7 +26,7 @@ You can also perform one-time interpolations that do not update on data change b
### 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](../api/directives.html#v-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/directives.html#v-html):
```html
Using mustaches: {{ rawHtml }}
@@ -38,7 +38,7 @@ The double mustaches interprets the data as plain text, not HTML. In order to ou
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](https://en.wikipedia.org/wiki/Cross-site_scripting). Only use HTML interpolation on trusted content and **never** on user-provided content
+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 HTML interpolation on trusted content and **never** on user-provided content.
:::
### Attributes
@@ -145,7 +145,7 @@ You'll see other examples of modifiers later, [for `v-on`](events.md#event-modif
## 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](https://en.wikipedia.org/wiki/Single-page_application), where Vue manages every template. Therefore, Vue provides special shorthands for two of the most often used directives, `v-bind` and `v-on`:
+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 an [SPA](https://en.wikipedia.org/wiki/Single-page_application), 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
diff --git a/src/guide/testing.md b/src/guide/testing.md
index ade7ba4910..3b5f3516fb 100644
--- a/src/guide/testing.md
+++ b/src/guide/testing.md
@@ -58,7 +58,7 @@ Mocha is a JavaScript test framework that is focused on being flexible. Because
### Introduction
-To test most Vue components, they must be mounted to the DOM (either virtual or real) in order to fully assert that they are working. This is another framework-agnostic concept. As a result, component testing frameworks were created to give users the ability to do this in a reliable way while also providing Vue-specific conveniences such as integrations for Vuex, Vue Router, and other Vue plugins.
+To test most Vue components, they must be mounted to the DOM (either virtual or real) in order to fully assert that they are working. This is another framework-agnostic concept. As a result, component testing frameworks were created to give users the ability to do this reliably while also providing Vue-specific conveniences such as integrations for Vuex, Vue Router, and other Vue plugins.
### Choosing Your Framework
@@ -70,7 +70,7 @@ It should be no surprise that one of the first criteria is that a component test
#### First-class error reporting
-When tests fail, it is critical that your component testing framework provides useful error logs that help to minimize the amount of time it takes to debug the problem. In addition to simply telling you what test fails, they should also provides context for why a test fails, e.g., what is expected vs what was received.
+When tests fail, it is critical that your component testing framework provides useful error logs that help to minimize the amount of time it takes to debug the problem. In addition to simply telling you what test fails, they should also provide context for why a test fails, e.g., what is expected vs what was received.
### Recommendations
diff --git a/src/guide/transitions-list.md b/src/guide/transitions-list.md
index d22ff24813..fa146ed64f 100644
--- a/src/guide/transitions-list.md
+++ b/src/guide/transitions-list.md
@@ -8,7 +8,7 @@ So far, we've managed transitions for:
So what about for when we have a whole list of items we want to render simultaneously, for example with `v-for`? In this case, we'll use the `` component. Before we dive into an example though, there are a few things that are important to know about this component:
- By default, it doesn't render a wrapper element, but you can specify an element to be rendered with the `tag` attribute.
-- [Transition modes](/guide/transitions-enterleave#transition-modes) are not available, because we are no longer alternating between mutually exclusive elements.
+- [Transition modes](/guide/transitions-enterleave.html#transition-modes) are not available, because we are no longer alternating between mutually exclusive elements.
- Elements inside are **always required** to have a unique `key` attribute.
- CSS transition classes will be applied to inner elements and not to the group/container itself.
diff --git a/src/guide/transitions-overview.md b/src/guide/transitions-overview.md
index eb98a33ee0..ee20b1c262 100644
--- a/src/guide/transitions-overview.md
+++ b/src/guide/transitions-overview.md
@@ -176,7 +176,7 @@ Easing can also convey the quality of material being animated. Take this pen for
-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](https://cubic-bezier.com/#.17,.67,.83,.67) by Lea Verou is very helpful for exploring this.
+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 the cubic-bezier function's parameters, [this playground](https://cubic-bezier.com/#.17,.67,.83,.67) 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.
diff --git a/src/guide/typescript-support.md b/src/guide/typescript-support.md
index 53e2593f5c..c8363a08ef 100644
--- a/src/guide/typescript-support.md
+++ b/src/guide/typescript-support.md
@@ -86,9 +86,9 @@ Or, if you want to combine TypeScript with a [JSX `render` function](/guide/rend
### Editor Support
-For developing Vue applications with TypeScript, we strongly recommend using [Visual Studio Code](https://code.visualstudio.com/), which provides great out-of-the-box support for TypeScript. If you are using [single-file components](./single-file-component.html) (SFCs), get the awesome [Vetur extension](https://github.com/vuejs/vetur), which provides TypeScript inference inside SFCs and many other great features.
+For developing Vue applications with TypeScript, we strongly recommend using [Visual Studio Code](https://code.visualstudio.com/), which provides great out-of-the-box support for TypeScript. If you are using [single-file components](./single-file-component.html) (SFCs), get the awesome [Volar extension](https://github.com/johnsoncodehk/volar), which provides TypeScript inference inside SFCs and many other great features.
-[WebStorm](https://www.jetbrains.com/webstorm/) also provides out-of-the-box support for both TypeScript and Vue.
+[WebStorm](https://www.jetbrains.com/webstorm/) provides out of the box support for both TypeScript and Vue. Other JetBrains IDEs also support them, either out of the box or via [this free plugin](https://plugins.jetbrains.com/plugin/9442-vue-js).
## Defining Vue Components
@@ -247,6 +247,7 @@ interface Book {
const Component = defineComponent({
props: {
name: String,
+ id: [Number, String],
success: { type: String },
callback: {
type: Function as PropType<() => void>
@@ -254,6 +255,9 @@ const Component = defineComponent({
book: {
type: Object as PropType,
required: true
+ },
+ metadata: {
+ type: null // metadata is typed as any
}
}
})
@@ -486,3 +490,36 @@ export default defineComponent({
}
})
```
+
+### Typing Event Handlers
+
+When dealing with native DOM events, it might be useful to type the argument we pass to the handler correctly. Let's take a look at this example:
+
+```vue
+
+
+
+
+
+```
+
+As you can see, without annotating the `evt` argument correctly, TypeScript will throw an error when we try to access the value of the `` element. The solution is to cast the event target with a correct type:
+
+```ts
+const handleChange = (evt: Event) => {
+ console.log((evt.target as HTMLInputElement).value)
+}
+```
diff --git a/src/guide/web-components.md b/src/guide/web-components.md
new file mode 100644
index 0000000000..be4d3de86f
--- /dev/null
+++ b/src/guide/web-components.md
@@ -0,0 +1,251 @@
+# Vue and Web Components
+
+[Web Components](https://developer.mozilla.org/en-US/docs/Web/Web_Components) is an umbrella term for a set of web native APIs that allows developers to create reusable custom elements.
+
+We consider Vue and Web Components to be primarily complementary technologies. Vue has excellent support for both consuming and creating custom elements. Whether you are integrating custom elements into an existing Vue application, or using Vue to build and distribute custom elements, you are in good company.
+
+## Using Custom Elements in Vue
+
+Vue [scores a perfect 100% in the Custom Elements Everywhere tests](https://custom-elements-everywhere.com/libraries/vue/results/results.html). Consuming custom elements inside a Vue application largely works the same as using native HTML elements, with a few things to keep in mind:
+
+### Skipping Component Resolution
+
+By default, Vue will attempt to resolve a non-native HTML tag as a registered Vue component before falling back to rendering it as a custom element. This will cause Vue to emit a "failed to resolve component" warning during development. To let Vue know that certain elements should be treated as custom elements and skip component resolution, we can specify the [`compilerOptions.isCustomElement` option](/api/application-config.html#compileroptions).
+
+If you are using Vue with a build setup, the option should be passed via build configs since it is a compile-time option.
+
+#### Example In-Browser Config
+
+```js
+// Only works if using in-browser compilation.
+// If using build tools, see config examples below.
+app.config.compilerOptions.isCustomElement = tag => tag.includes('-')
+```
+
+#### Example Vite Config
+
+```js
+// vite.config.js
+import vue from '@vitejs/plugin-vue'
+
+export default {
+ plugins: [
+ vue({
+ template: {
+ compilerOptions: {
+ // treat all tags with a dash as custom elements
+ isCustomElement: tag => tag.includes('-')
+ }
+ }
+ })
+ ]
+}
+```
+
+#### Example Vue CLI Config
+
+```js
+// vue.config.js
+module.exports = {
+ chainWebpack: config => {
+ config.module
+ .rule('vue')
+ .use('vue-loader')
+ .tap(options => ({
+ ...options,
+ compilerOptions: {
+ // treat any tag that starts with ion- as custom elements
+ isCustomElement: tag => tag.startsWith('ion-')
+ }
+ }))
+ }
+}
+```
+
+### Passing DOM Properties
+
+Since DOM attributes can only be strings, we need to pass complex data to custom elements as DOM properties. When setting props on a custom element, Vue 3 automatically checks DOM-property presence using the `in` operator and will prefer setting the value as a DOM property if the key is present. This means that, in most cases, you won't need to think about this if the custom element follows the [recommended best practices](https://developers.google.com/web/fundamentals/web-components/best-practices#aim-to-keep-primitive-data-attributes-and-properties-in-sync,-reflecting-from-property-to-attribute,-and-vice-versa.).
+
+However, there could be rare cases where the data must be passed as a DOM property, but the custom element does not properly define/reflect the property (causing the `in` check to fail). In this case, you can force a `v-bind` binding to be set as a DOM property using the `.prop` modifier:
+
+```html
+
+
+
+
+```
+
+## Building Custom Elements with Vue
+
+The primary benefit of custom elements is that they can be used with any framework, or even without a framework. This makes them ideal for distributing components where the end consumer may not be using the same frontend stack, or when you want to insulate the end application from the implementation details of the components it uses.
+
+### defineCustomElement
+
+Vue supports creating custom elements using exactly the same Vue component APIs via the [`defineCustomElement`](/api/global-api.html#definecustomelement) method. The method accepts the same argument as [`defineComponent`](/api/global-api.html#definecomponent), but instead returns a custom element constructor that extends `HTMLElement`:
+
+```html
+
+```
+
+```js
+import { defineCustomElement } from 'vue'
+
+const MyVueElement = defineCustomElement({
+ // normal Vue component options here
+ props: {},
+ emits: {},
+ template: `...`,
+
+ // defineCustomElement only: CSS to be injected into shadow root
+ styles: [`/* inlined css */`]
+})
+
+// Register the custom element.
+// After registration, all `` tags
+// on the page will be upgraded.
+customElements.define('my-vue-element', MyVueElement)
+
+// You can also programmatically instantiate the element:
+// (can only be done after registration)
+document.body.appendChild(
+ new MyVueElement({
+ // initial props (optional)
+ })
+)
+```
+
+#### Lifecycle
+
+- A Vue custom element will mount an internal Vue component instance inside its shadow root when the element's [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks) is called for the first time.
+
+- When the element's `disconnectedCallback` is invoked, Vue will check whether the element is detached from the document after a microtask tick.
+
+ - If the element is still in the document, it's a move and the component instance will be preserved;
+
+ - If the element is detached from the document, it's a removal and the component instance will be unmounted.
+
+#### Props
+
+- All props declared using the `props` option will be defined on the custom element as properties. Vue will automatically handle the reflection between attributes / properties where appropriate.
+
+ - Attributes are always reflected to corresponding properties.
+
+ - Properties with primitive values (`string`, `boolean` or `number`) are reflected as attributes.
+
+- Vue also automatically casts props declared with `Boolean` or `Number` types into the desired type when they are set as attributes (which are always strings). For example given the following props declaration:
+
+ ```js
+ props: {
+ selected: Boolean,
+ index: Number
+ }
+ ```
+
+ And the custom element usage:
+
+ ```html
+
+ ```
+
+ In the component, `selected` will be cast to `true` (boolean) and `index` will be cast to `1` (number).
+
+#### Events
+
+Events emitted via `this.$emit` or setup `emit` are dispatched as native [CustomEvents](https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events#adding_custom_data_%E2%80%93_customevent) on the custom element. Additional event arguments (payload) will be exposed as an array on the CustomEvent object as its `details` property.
+
+#### Slots
+
+Inside the component, slots can be rendered using the `` element as usual. However when consuming the resulting element, it only accepts [native slots syntax](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots):
+
+- [Scoped slots](/guide/component-slots.html#scoped-slots) are not supported.
+
+- When passing named slots, use the `slot` attribute instead of the `v-slot` directive:
+
+ ```html
+
+
hello
+
+ ```
+
+#### Provide / Inject
+
+The [Provide / Inject API](/guide/component-provide-inject.html#provide-inject) and its [Composition API equivalent](/api/composition-api.html#provide-inject) also work between Vue-defined custom elements. However, note that this works **only between custom elements**. i.e. a Vue-defined custom element won't be able to inject properties provided by a non-custom-element Vue component.
+
+### SFC as Custom Element
+
+`defineCustomElement` also works with Vue Single File Components (SFCs). However, with the default tooling setup, the `