diff --git a/src/v2/style-guide/index.md b/src/v2/style-guide/index.md index 7c9b61424e..cdad30355d 100644 --- a/src/v2/style-guide/index.md +++ b/src/v2/style-guide/index.md @@ -7,45 +7,12 @@ This is the official style guide for Vue-specific code. If you use Vue in a proj For the most part, we also avoid suggestions about JavaScript or HTML in general. We don't mind whether you use semicolons or trailing commas. We don't mind whether your HTML uses single-quotes or double-quotes for attribute values. Some exceptions will exist however, where we've found that a particular pattern is helpful in the context of Vue. -> **Soon, we'll also provide tips for enforcement.** Sometimes you'll simply have to be disciplined, but wherever possible, we'll try to show you how to use ESLint and other automated processes to make enforcement simpler. -Finally, we've split rules into four categories: +## Naming +### DO use multi-word component names - -## Rule Categories - -### Priority A: Essential - -These rules help prevent errors, so learn and abide by them at all costs. Exceptions may exist, but should be very rare and only be made by those with expert knowledge of both JavaScript and Vue. - -### Priority B: Strongly Recommended - -These rules have been found to improve readability and/or developer experience in most projects. Your code will still run if you violate them, but violations should be rare and well-justified. - -### Priority C: Recommended - -Where multiple, equally good options exist, an arbitrary choice can be made to ensure consistency. In these rules, we describe each acceptable option and suggest a default choice. That means you can feel free to make a different choice in your own codebase, as long as you're consistent and have a good reason. Please do have a good reason though! By adapting to the community standard, you will: - -1. train your brain to more easily parse most of the community code you encounter -2. be able to copy and paste most community code examples without modification -3. often find new hires are already accustomed to your preferred coding style, at least in regards to Vue - -### Priority D: Use with Caution - -Some features of Vue exist to accommodate rare edge cases or smoother migrations from a legacy code base. When overused however, they can make your code more difficult to maintain or even become a source of bugs. These rules shine a light on potentially risky features, describing when and why they should be avoided. - - - -## Priority A Rules: Essential (Error Prevention) - - - -### Multi-word component names essential - -**Component names should always be multi-word, except for root `App` components, and built-in components provided by Vue, such as `` or ``.** - -This [prevents conflicts](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name) with existing and future HTML elements, since all HTML elements are a single word. +Component names should always be multi-word, except for root `App` components, and built-in components provided by Vue, such as `` or ``. This [prevents conflicts](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name) with existing and future HTML elements, since all HTML elements are a single word. {% raw %}
{% endraw %} #### Bad @@ -81,13 +48,9 @@ export default { ``` {% raw %}
{% endraw %} +### DO use a prefix for base component names - -### Component data essential - -**Component `data` must be a function.** - -When using the `data` property on a component (i.e. anywhere except on `new Vue`), the value must be a function that returns an object. +Base components (a.k.a. presentational, dumb, or pure components) that apply app-specific styling and conventions should all begin with a specific prefix, such as `Base`, `App`, or `V`. {% raw %}
@@ -96,91 +59,105 @@ When using the `data` property on a component (i.e. anywhere except on `new Vue` {% endraw %} -When the value of `data` is an object, it's shared across all instances of a component. Imagine, for example, a `TodoList` component with this data: +These components lay the foundation for consistent styling and behavior in your application. They may **only** contain: -``` js -data: { - listTitle: '', - todos: [] -} -``` +- HTML elements, +- other base components, and +- 3rd-party UI components. -We might want to reuse this component, allowing users to maintain multiple lists (e.g. for shopping, wishlists, daily chores, etc). There's a problem though. Since every instance of the component references the same data object, changing the title of one list will also change the title of every other list. The same is true for adding/editing/deleting a todo. +But they'll **never** contain global state (e.g. from a Vuex store). -Instead, we want each component instance to only manage its own data. For that to happen, each instance must generate a unique data object. In JavaScript, this can be accomplished by returning the object in a function: +Their names often include the name of an element they wrap (e.g. `BaseButton`, `BaseTable`), unless no element exists for their specific purpose (e.g. `BaseIcon`). If you build similar components for a more specific context, they will almost always consume these components (e.g. `BaseButton` may be used in `ButtonSubmit`). + +Some advantages of this convention: + +- When organized alphabetically in editors, your app's base components are all listed together, making them easier to identify. + +- Since component names should always be multi-word, this convention prevents you from having to choose an arbitrary prefix for simple component wrappers (e.g. `MyButton`, `VueButton`). + +- Since these components are so frequently used, you may want to simply make them global instead of importing them everywhere. A prefix makes this possible with Webpack: + + ``` js + var requireComponent = require.context("./src", true, /Base[A-Z]\w+\.(vue|js)$/) + requireComponent.keys().forEach(function (fileName) { + var baseComponentConfig = requireComponent(fileName) + baseComponentConfig = baseComponentConfig.default || baseComponentConfig + var baseComponentName = baseComponentConfig.name || ( + fileName + .replace(/^.+\//, '') + .replace(/\.\w+$/, '') + ) + Vue.component(baseComponentName, baseComponentConfig) + }) + ``` -``` js -data: function () { - return { - listTitle: '', - todos: [] - } -} -``` {% raw %}
{% endraw %} {% raw %}
{% endraw %} #### Bad -``` js -Vue.component('some-comp', { - data: { - foo: 'bar' - } -}) ``` - -``` js -export default { - data: { - foo: 'bar' - } -} +components/ +|- MyButton.vue +|- VueTable.vue +|- Icon.vue ``` {% raw %}
{% endraw %} {% raw %}
{% endraw %} #### Good -``` js -Vue.component('some-comp', { - data: function () { - return { - foo: 'bar' - } - } -}) + +``` +components/ +|- BaseButton.vue +|- BaseTable.vue +|- BaseIcon.vue ``` -``` js -// In a .vue file -export default { - data () { - return { - foo: 'bar' - } - } -} +``` +components/ +|- AppButton.vue +|- AppTable.vue +|- AppIcon.vue ``` -``` js -// It's OK to use an object directly in a root -// Vue instance, since only a single instance -// will ever exist. -new Vue({ - data: { - foo: 'bar' - } -}) +``` +components/ +|- VButton.vue +|- VTable.vue +|- VIcon.vue ``` {% raw %}
{% endraw %} +### DO prefix single-instance component names with "The" + +Components that should only ever have a single active instance should begin with the `The` prefix, to denote that there can be only one. + +This does not mean the component is only used in a single page, but it will only be used once _per page_. These components never accept any props, since they are specific to your app, not their context within your app. If you find the need to add props, it's a good indication that this is actually a reusable component that is only used once per page _for now_. +{% raw %}
{% endraw %} +#### Bad -### Prop definitions essential +``` +components/ +|- Heading.vue +|- MySidebar.vue +``` +{% raw %}
{% endraw %} -**Prop definitions should be as detailed as possible.** +{% raw %}
{% endraw %} +#### Good -In committed code, prop definitions should always be as detailed as possible, specifying at least type(s). +``` +components/ +|- TheHeading.vue +|- TheSidebar.vue +``` +{% raw %}
{% endraw %} + +### PREFER prefixing tightly-coupled components' names with the parent component name + +If a component only makes sense in the context of a single parent component, that relationship should be evident in its name. Since editors typically organize files alphabetically, this also keeps these related files next to each other. {% raw %}
@@ -189,57 +166,72 @@ In committed code, prop definitions should always be as detailed as possible, sp {% endraw %} -Detailed [prop definitions](https://vuejs.org/v2/guide/components.html#Prop-Validation) have two advantages: +You might be tempted to solve this problem by nesting child components in directories named after their parent. For example: -- They document the API of the component, so that it's easy to see how the component is meant to be used. -- In development, Vue will warn you if a component is ever provided incorrectly formatted props, helping you catch potential sources of error. +``` +components/ +|- TodoList/ + |- Item/ + |- index.vue + |- Button.vue + |- index.vue +``` + +or: + +``` +components/ +|- TodoList/ + |- Item/ + |- Button.vue + |- Item.vue +|- TodoList.vue +``` + +This isn't recommended, as it results in: + +- Many files with similar names, making rapid file switching in code editors more difficult. +- Many nested sub-directories, which increases the time it takes to browse components in an editor's sidebar. {% raw %}
{% endraw %} {% raw %}
{% endraw %} #### Bad -``` js -// This is only OK when prototyping -props: ['status'] +``` +components/ +|- TodoList.vue +|- TodoItem.vue +|- TodoButton.vue +``` + +``` +components/ +|- SearchSidebar.vue +|- NavigationForSearchSidebar.vue ``` {% raw %}
{% endraw %} {% raw %}
{% endraw %} #### Good -``` js -props: { - status: String -} +``` +components/ +|- TodoList.vue +|- TodoListItem.vue +|- TodoListItemButton.vue ``` -``` js -// Even better! -props: { - status: { - type: String, - required: true, - validator: function (value) { - return [ - 'syncing', - 'synced', - 'version-conflict', - 'error' - ].indexOf(value) !== -1 - } - } -} +``` +components/ +|- SearchSidebar.vue +|- SearchSidebarNavigation.vue ``` {% raw %}
{% endraw %} +### DO use a consistent order of words in component names - -### Keyed `v-for` essential - -**Always use `key` with `v-for`.** - -`key` with `v-for` is _always_ required on components, in order to maintain internal component state down the subtree. Even for elements though, it's a good practice to maintain predictable behavior, such as [object constancy](https://bost.ocks.org/mike/constancy/) in animations. +Component names should start with the highest-level (often most general) words and end with descriptive modifying words. {% raw %}
@@ -248,230 +240,144 @@ props: { {% endraw %} -Let's say you have a list of todos: - -``` js -data: function () { - return { - todos: [ - { - id: 1, - text: 'Learn to use v-for' - }, - { - id: 2, - text: 'Learn to use key' - } - ] - } -} -``` +You may be wondering: -Then you sort them alphabetically. When updating the DOM, Vue will optimize rendering to perform the cheapest DOM mutations possible. That might mean deleting the first todo element, then adding it again at the end of the list. +> "Why would we force component names to use less natural language?" -The problem is, there are cases where it's important not to delete elements that will remain in the DOM. For example, you may want to use `` to animate list sorting, or maintain focus if the rendered element is an ``. In these cases, adding a unique key for each item (e.g. `:key="todo.id"`) will tell Vue how to behave more predictably. +In natural English, adjectives and other descriptors do typically appear before the nouns, while exceptions require connector words. For example: -In our experience, it's better to _always_ add a unique key, so that you and your team simply never have to worry about these edge cases. Then in the rare, performance-critical scenarios where object constancy isn't necessary, you can make a conscious exception. +- Coffee _with_ milk +- Soup _of the_ day +- Visitor _to the_ museum -{% raw %}
{% endraw %} +You can definitely include these connector words in component names if you'd like, but the order is still important. -{% raw %}
{% endraw %} -#### Bad +Also note that **what's considered "highest-level" will be contextual to your app**. For example, imagine an app with a search form. It may include components like this one: -``` html -
    -
  • - {{ todo.text }} -
  • -
``` -{% raw %}
{% endraw %} - -{% raw %}
{% endraw %} -#### Good - -``` html -
    -
  • - {{ todo.text }} -
  • -
+components/ +|- ClearSearchButton.vue +|- ExcludeFromSearchInput.vue +|- LaunchOnStartupCheckbox.vue +|- RunSearchButton.vue +|- SearchInput.vue +|- TermsCheckbox.vue ``` -{% raw %}
{% endraw %} +As you might notice, it's quite difficult to see which components are specific to the search. Now let's rename the components according to the rule: +``` +components/ +|- SearchButtonClear.vue +|- SearchButtonRun.vue +|- SearchInputExcludeGlob.vue +|- SearchInputQuery.vue +|- SettingsCheckboxLaunchOnStartup.vue +|- SettingsCheckboxTerms.vue +``` -### Avoid `v-if` with `v-for` essential - -**Never use `v-if` on the same element as `v-for`.** - -There are two common cases where this can be tempting: +Since editors typically organize files alphabetically, all the important relationships between components are now evident at a glance. -- To filter items in a list (e.g. `v-for="user in users" v-if="user.isActive"`). In these cases, replace `users` with a new computed property that returns your filtered list (e.g. `activeUsers`). +You might be tempted to solve this problem differently, nesting all the search components under a "search" directory, then all the settings components under a "settings" directory. We only recommend considering this approach in very large apps (e.g. 100+ components), for these reasons: -- To avoid rendering a list if it should be hidden (e.g. `v-for="user in users" v-if="shouldShowUsers"`). In these cases, move the `v-if` to a container element (e.g. `ul`, `ol`). +- It generally takes more time to navigate through nested sub-directories, than scrolling through a single `components` directory. +- Name conflicts (e.g. multiple `ButtonDelete.vue` components) make it more difficult to quickly navigate to a specific component in a code editor. +- Refactoring becomes more difficult, because find-and-replace often isn't sufficient to update relative references to a moved component. -{% raw %} -
- -

Detailed Explanation

-
-{% endraw %} +{% raw %}
{% endraw %} -When Vue processes directives, `v-for` has a higher priority than `v-if`, so that this template: +{% raw %}
{% endraw %} +#### Bad -``` html -
    -
  • - {{ user.name }} -
  • -
``` - -Will be evaluated similar to: - -``` js -this.users.map(function (user) { - if (user.isActive) { - return user.name - } -}) +components/ +|- ClearSearchButton.vue +|- ExcludeFromSearchInput.vue +|- LaunchOnStartupCheckbox.vue +|- RunSearchButton.vue +|- SearchInput.vue +|- TermsCheckbox.vue ``` +{% raw %}
{% endraw %} -So even if we only render elements for a small fraction of users, we have to iterate over the entire list every time we re-render, whether or not the set of active users has changed. - -By iterating over a computed property instead, like this: +{% raw %}
{% endraw %} +#### Good -``` js -computed: { - activeUsers: function () { - return this.users.filter(function (user) { - return user.isActive - }) - } -} ``` - -``` html -
    -
  • - {{ user.name }} -
  • -
+components/ +|- SearchButtonClear.vue +|- SearchButtonRun.vue +|- SearchInputQuery.vue +|- SearchInputExcludeGlob.vue +|- SettingsCheckboxTerms.vue +|- SettingsCheckboxLaunchOnStartup.vue ``` +{% raw %}
{% endraw %} -We get the following benefits: +### AVOID abbreviations in component names -- The filtered list will _only_ be re-evaluated if there are relevant changes to the `users` array, making filtering much more efficient. -- Using `v-for="user in activeUsers"`, we _only_ iterate over active users during render, making rendering much more efficient. -- Logic is now decoupled from the presentation layer, making maintenance (change/extension of logic) much easier. +Component names should prefer full words over abbreviations. The autocompletion in editors make the cost of writing longer names very low, while the clarity they provide is invaluable. Uncommon abbreviations, in particular, should always be avoided. -We get similar benefits from updating: +{% raw %}
{% endraw %} +#### Bad -``` html -
    -
  • - {{ user.name }} -
  • -
``` +components/ +|- SdSettings.vue +|- UProfOpts.vue +``` +{% raw %}
{% endraw %} -to: +{% raw %}
{% endraw %} +#### Good -``` html -
    -
  • - {{ user.name }} -
  • -
``` +components/ +|- StudentDashboardSettings.vue +|- UserProfileOptions.vue +``` +{% raw %}
{% endraw %} -By moving the `v-if` to a container element, we're no longer checking `shouldShowUsers` for _every_ user in the list. Instead, we check it once and don't even evaluate the `v-for` if `shouldShowUsers` is false. -{% raw %}{% endraw %} +## Casing + +### PREFER using PascalCase or kebab-case for single-file component filename + +Filenames of [single-file components](../guide/single-file-components.html) should either be always PascalCase or always kebab-case. + +PascalCase works best with autocompletion in code editors, as it's consistent with how we reference components in JS(X) and templates, wherever possible. However, mixed case filenames can sometimes create issues on case-insensitive file systems, which is why kebab-case is also perfectly acceptable. {% raw %}
{% endraw %} #### Bad -``` html -
    -
  • - {{ user.name }} -
  • -
+``` +components/ +|- mycomponent.vue ``` -``` html -
    -
  • - {{ user.name }} -
  • -
+``` +components/ +|- myComponent.vue ``` {% raw %}
{% endraw %} {% raw %}
{% endraw %} #### Good -``` html -
    -
  • - {{ user.name }} -
  • -
+``` +components/ +|- MyComponent.vue ``` -``` html -
    -
  • - {{ user.name }} -
  • -
+``` +components/ +|- my-component.vue ``` {% raw %}
{% endraw %} +### PREFER using PascalCase for component names in TS/JS(X) - -### Component style scoping essential - -**For applications, styles in a top-level `App` component and in layout components may be global, but all other components should always be scoped.** - -This is only relevant for [single-file components](../guide/single-file-components.html). It does _not_ require that the [`scoped` attribute](https://vue-loader.vuejs.org/en/features/scoped-css.html) be used. Scoping could be through [CSS modules](https://vue-loader.vuejs.org/en/features/css-modules.html), a class-based strategy such as [BEM](http://getbem.com/), or another library/convention. - -**Component libraries, however, should prefer a class-based strategy instead of using the `scoped` attribute.** - -This makes overriding internal styles easier, with human-readable class names that don't have too high specificity, but are still very unlikely to result in a conflict. +Component names in TS/TSX/JS/[JSX](../guide/render-function.html#JSX) should always be PascalCase, though they may be kebab-case inside strings for simpler applications that only use global component registration through `Vue.component`. {% raw %}
@@ -480,273 +386,162 @@ This makes overriding internal styles easier, with human-readable class names th {% endraw %} -If you are developing a large project, working with other developers, or sometimes include 3rd-party HTML/CSS (e.g. from Auth0), consistent scoping will ensure that your styles only apply to the components they are meant for. +In JavaScript, PascalCase is the convention for classes and prototype constructors - essentially, anything that can have distinct instances. Vue components also have instances, so it makes sense to also use PascalCase. As an added benefit, using PascalCase within JSX (and templates) allows readers of the code to more easily distinguish between components and HTML elements. -Beyond the `scoped` attribute, using unique class names can help ensure that 3rd-party CSS does not apply to your own HTML. For example, many projects use the `button`, `btn`, or `icon` class names, so even if not using a strategy such as BEM, adding an app-specific and/or component-specific prefix (e.g. `ButtonClose-icon`) can provide some protection. +However, for applications that use **only** global component definitions via `Vue.component`, we recommend kebab-case instead. The reasons are: + +- It's rare that global components are ever referenced in JavaScript, so following a convention for JavaScript makes less sense. +- These applications always include many in-DOM templates, where [kebab-case **must** be used](#Component-name-casing-in-templates-strongly-recommended). {% raw %}
{% endraw %} {% raw %}
{% endraw %} #### Bad -``` html - +``` js +Vue.component('myComponent', { + // ... +}) +``` - ``` {% raw %}
{% endraw %} {% raw %}
{% endraw %} #### Good -``` html - - - - -``` - -``` html - - - - -``` - -``` html - - - - -``` -{% raw %}
{% endraw %} - - - -### Private property names essential - -**Use module scoping to keep private functions inaccessible from the outside. If that's not possible, always use the `$_` prefix for custom private properties in a plugin, mixin, etc that should not be considered public API. Then to avoid conflicts with code by other authors, also include a named scope (e.g. `$_yourPluginName_`).** - -{% raw %} -
- -

Detailed Explanation

-
-{% endraw %} - -Vue uses the `_` prefix to define its own private properties, so using the same prefix (e.g. `_update`) risks overwriting an instance property. Even if you check and Vue is not currently using a particular property name, there is no guarantee a conflict won't arise in a later version. - -As for the `$` prefix, its purpose within the Vue ecosystem is special instance properties that are exposed to the user, so using it for _private_ properties would not be appropriate. - -Instead, we recommend combining the two prefixes into `$_`, as a convention for user-defined private properties that guarantee no conflicts with Vue. - -{% raw %}
{% endraw %} - -{% raw %}
{% endraw %} -#### Bad - -``` js -var myGreatMixin = { - // ... - methods: { - update: function () { - // ... - } - } -} -``` - -``` js -var myGreatMixin = { - // ... - methods: { - _update: function () { - // ... - } - } -} -``` - ``` js -var myGreatMixin = { +Vue.component('MyComponent', { // ... - methods: { - $update: function () { - // ... - } - } -} +}) ``` ``` js -var myGreatMixin = { +Vue.component('my-component', { // ... - methods: { - $_update: function () { - // ... - } - } -} +}) ``` -{% raw %}
{% endraw %} - -{% raw %}
{% endraw %} -#### Good - ``` js -var myGreatMixin = { - // ... - methods: { - $_myGreatMixin_update: function () { - // ... - } - } -} +import MyComponent from './MyComponent.vue' ``` ``` js -// Even better! -var myGreatMixin = { - // ... - methods: { - publicMethod() { - // ... - myPrivateFunction() - } - } -} - -function myPrivateFunction() { +export default { + name: 'MyComponent', // ... } - -export default myGreatMixin ``` {% raw %}
{% endraw %} +### PREFER using PascalCase for component tag names in templates +In most projects, component names should always be PascalCase in [single-file components](../guide/single-file-components.html) and string templates - but kebab-case in DOM templates. -## Priority B Rules: Strongly Recommended (Improving Readability) - - +PascalCase has a few advantages over kebab-case: -### Component files strongly recommended +- Editors can autocomplete component names in templates, because PascalCase is also used in JavaScript. +- `` is more visually distinct from a single-word HTML element than ``, because there are two character differences (the two capitals), rather than just one (a hyphen). +- If you use any non-Vue custom elements in your templates, such as a web component, PascalCase ensures that your Vue components remain distinctly visible. -**Whenever a build system is available to concatenate files, each component should be in its own file.** +Unfortunately, due to HTML's case insensitivity, DOM templates must still use kebab-case. -This helps you to more quickly find a component when you need to edit it or review how to use it. +Also note that if you've already invested heavily in kebab-case, consistency with HTML conventions and being able to use the same casing across all your projects may be more important than the advantages listed above. In those cases, **using kebab-case everywhere is also acceptable.** {% raw %}
{% endraw %} #### Bad -``` js -Vue.component('TodoList', { - // ... -}) +``` html + + +``` -Vue.component('TodoItem', { - // ... -}) +``` html + + +``` + +``` html + + ``` {% raw %}
{% endraw %} {% raw %}
{% endraw %} #### Good -``` -components/ -|- TodoList.js -|- TodoItem.js +``` html + + ``` +``` html + + ``` -components/ -|- TodoList.vue -|- TodoItem.vue -``` -{% raw %}
{% endraw %} - +OR -### Single-file component filename casing strongly recommended +``` html + + +``` +{% raw %}{% endraw %} -**Filenames of [single-file components](../guide/single-file-components.html) should either be always PascalCase or always kebab-case.** +### PREFER camelCase for prop names declaration and kebab-case in templates and JSX -PascalCase works best with autocompletion in code editors, as it's consistent with how we reference components in JS(X) and templates, wherever possible. However, mixed case filenames can sometimes create issues on case-insensitive file systems, which is why kebab-case is also perfectly acceptable. +We're simply following the conventions of each language. Within JavaScript, camelCase is more natural. Within HTML, kebab-case is. {% raw %}
{% endraw %} #### Bad -``` -components/ -|- mycomponent.vue +``` js +props: { + 'greeting-text': String +} ``` -``` -components/ -|- myComponent.vue -``` +{% codeblock lang:html %} + +{% endcodeblock %} {% raw %}
{% endraw %} {% raw %}
{% endraw %} #### Good -``` -components/ -|- MyComponent.vue +``` js +props: { + greetingText: String +} ``` -``` -components/ -|- my-component.vue -``` +{% codeblock lang:html %} + +{% endcodeblock %} {% raw %}
{% endraw %} +## Templating -### Base component names strongly recommended +### DO use `key` with `v-for` -**Base components (a.k.a. presentational, dumb, or pure components) that apply app-specific styling and conventions should all begin with a specific prefix, such as `Base`, `App`, or `V`.** +`key` with `v-for` is _always_ required on components, in order to maintain internal component state down the subtree. Even for elements though, it's a good practice to maintain predictable behavior, such as [object constancy](https://bost.ocks.org/mike/constancy/) in animations. {% raw %}
@@ -755,521 +550,186 @@ components/ {% endraw %} -These components lay the foundation for consistent styling and behavior in your application. They may **only** contain: +Let's say you have a list of todos: -- HTML elements, -- other base components, and -- 3rd-party UI components. +``` js +data: function () { + return { + todos: [ + { + id: 1, + text: 'Learn to use v-for' + }, + { + id: 2, + text: 'Learn to use key' + } + ] + } +} +``` -But they'll **never** contain global state (e.g. from a Vuex store). +Then you sort them alphabetically. When updating the DOM, Vue will optimize rendering to perform the cheapest DOM mutations possible. That might mean deleting the first todo element, then adding it again at the end of the list. -Their names often include the name of an element they wrap (e.g. `BaseButton`, `BaseTable`), unless no element exists for their specific purpose (e.g. `BaseIcon`). If you build similar components for a more specific context, they will almost always consume these components (e.g. `BaseButton` may be used in `ButtonSubmit`). +The problem is, there are cases where it's important not to delete elements that will remain in the DOM. For example, you may want to use `` to animate list sorting, or maintain focus if the rendered element is an ``. In these cases, adding a unique key for each item (e.g. `:key="todo.id"`) will tell Vue how to behave more predictably. -Some advantages of this convention: +In our experience, it's better to _always_ add a unique key, so that you and your team simply never have to worry about these edge cases. Then in the rare, performance-critical scenarios where object constancy isn't necessary, you can make a conscious exception. -- When organized alphabetically in editors, your app's base components are all listed together, making them easier to identify. +{% raw %}
{% endraw %} -- Since component names should always be multi-word, this convention prevents you from having to choose an arbitrary prefix for simple component wrappers (e.g. `MyButton`, `VueButton`). +{% raw %}
{% endraw %} +#### Bad -- Since these components are so frequently used, you may want to simply make them global instead of importing them everywhere. A prefix makes this possible with Webpack: - - ``` js - var requireComponent = require.context("./src", true, /Base[A-Z]\w+\.(vue|js)$/) - requireComponent.keys().forEach(function (fileName) { - var baseComponentConfig = requireComponent(fileName) - baseComponentConfig = baseComponentConfig.default || baseComponentConfig - var baseComponentName = baseComponentConfig.name || ( - fileName - .replace(/^.+\//, '') - .replace(/\.\w+$/, '') - ) - Vue.component(baseComponentName, baseComponentConfig) - }) - ``` - -{% raw %}{% endraw %} - -{% raw %}
{% endraw %} -#### Bad - -``` -components/ -|- MyButton.vue -|- VueTable.vue -|- Icon.vue -``` -{% raw %}
{% endraw %} - -{% raw %}
{% endraw %} -#### Good - -``` -components/ -|- BaseButton.vue -|- BaseTable.vue -|- BaseIcon.vue -``` - -``` -components/ -|- AppButton.vue -|- AppTable.vue -|- AppIcon.vue -``` - -``` -components/ -|- VButton.vue -|- VTable.vue -|- VIcon.vue -``` -{% raw %}
{% endraw %} - - - -### Single-instance component names strongly recommended - -**Components that should only ever have a single active instance should begin with the `The` prefix, to denote that there can be only one.** - -This does not mean the component is only used in a single page, but it will only be used once _per page_. These components never accept any props, since they are specific to your app, not their context within your app. If you find the need to add props, it's a good indication that this is actually a reusable component that is only used once per page _for now_. - -{% raw %}
{% endraw %} -#### Bad - -``` -components/ -|- Heading.vue -|- MySidebar.vue -``` -{% raw %}
{% endraw %} - -{% raw %}
{% endraw %} -#### Good - -``` -components/ -|- TheHeading.vue -|- TheSidebar.vue -``` -{% raw %}
{% endraw %} - - - -### Tightly coupled component names strongly recommended - -**Child components that are tightly coupled with their parent should include the parent component name as a prefix.** - -If a component only makes sense in the context of a single parent component, that relationship should be evident in its name. Since editors typically organize files alphabetically, this also keeps these related files next to each other. - -{% raw %} -
- -

Detailed Explanation

-
-{% endraw %} - -You might be tempted to solve this problem by nesting child components in directories named after their parent. For example: - -``` -components/ -|- TodoList/ - |- Item/ - |- index.vue - |- Button.vue - |- index.vue -``` - -or: - -``` -components/ -|- TodoList/ - |- Item/ - |- Button.vue - |- Item.vue -|- TodoList.vue -``` - -This isn't recommended, as it results in: - -- Many files with similar names, making rapid file switching in code editors more difficult. -- Many nested sub-directories, which increases the time it takes to browse components in an editor's sidebar. - -{% raw %}
{% endraw %} - -{% raw %}
{% endraw %} -#### Bad - -``` -components/ -|- TodoList.vue -|- TodoItem.vue -|- TodoButton.vue -``` - -``` -components/ -|- SearchSidebar.vue -|- NavigationForSearchSidebar.vue -``` -{% raw %}
{% endraw %} - -{% raw %}
{% endraw %} -#### Good - -``` -components/ -|- TodoList.vue -|- TodoListItem.vue -|- TodoListItemButton.vue -``` - -``` -components/ -|- SearchSidebar.vue -|- SearchSidebarNavigation.vue -``` -{% raw %}
{% endraw %} - - - -### Order of words in component names strongly recommended - -**Component names should start with the highest-level (often most general) words and end with descriptive modifying words.** - -{% raw %} -
- -

Detailed Explanation

-
-{% endraw %} - -You may be wondering: - -> "Why would we force component names to use less natural language?" - -In natural English, adjectives and other descriptors do typically appear before the nouns, while exceptions require connector words. For example: - -- Coffee _with_ milk -- Soup _of the_ day -- Visitor _to the_ museum - -You can definitely include these connector words in component names if you'd like, but the order is still important. - -Also note that **what's considered "highest-level" will be contextual to your app**. For example, imagine an app with a search form. It may include components like this one: - -``` -components/ -|- ClearSearchButton.vue -|- ExcludeFromSearchInput.vue -|- LaunchOnStartupCheckbox.vue -|- RunSearchButton.vue -|- SearchInput.vue -|- TermsCheckbox.vue -``` - -As you might notice, it's quite difficult to see which components are specific to the search. Now let's rename the components according to the rule: - -``` -components/ -|- SearchButtonClear.vue -|- SearchButtonRun.vue -|- SearchInputExcludeGlob.vue -|- SearchInputQuery.vue -|- SettingsCheckboxLaunchOnStartup.vue -|- SettingsCheckboxTerms.vue -``` - -Since editors typically organize files alphabetically, all the important relationships between components are now evident at a glance. - -You might be tempted to solve this problem differently, nesting all the search components under a "search" directory, then all the settings components under a "settings" directory. We only recommend considering this approach in very large apps (e.g. 100+ components), for these reasons: - -- It generally takes more time to navigate through nested sub-directories, than scrolling through a single `components` directory. -- Name conflicts (e.g. multiple `ButtonDelete.vue` components) make it more difficult to quickly navigate to a specific component in a code editor. -- Refactoring becomes more difficult, because find-and-replace often isn't sufficient to update relative references to a moved component. - -{% raw %}
{% endraw %} - -{% raw %}
{% endraw %} -#### Bad - -``` -components/ -|- ClearSearchButton.vue -|- ExcludeFromSearchInput.vue -|- LaunchOnStartupCheckbox.vue -|- RunSearchButton.vue -|- SearchInput.vue -|- TermsCheckbox.vue -``` -{% raw %}
{% endraw %} - -{% raw %}
{% endraw %} -#### Good - -``` -components/ -|- SearchButtonClear.vue -|- SearchButtonRun.vue -|- SearchInputQuery.vue -|- SearchInputExcludeGlob.vue -|- SettingsCheckboxTerms.vue -|- SettingsCheckboxLaunchOnStartup.vue -``` -{% raw %}
{% endraw %} - - - -### Self-closing components strongly recommended - -**Components with no content should be self-closing in [single-file components](../guide/single-file-components.html), string templates, and [JSX](../guide/render-function.html#JSX) - but never in DOM templates.** - -Components that self-close communicate that they not only have no content, but are **meant** to have no content. It's the difference between a blank page in a book and one labeled "This page intentionally left blank." Your code is also cleaner without the unnecessary closing tag. - -Unfortunately, HTML doesn't allow custom elements to be self-closing - only [official "void" elements](https://www.w3.org/TR/html/syntax.html#void-elements). That's why the strategy is only possible when Vue's template compiler can reach the template before the DOM, then serve the DOM spec-compliant HTML. - -{% raw %}
{% endraw %} -#### Bad - -``` html - - -``` - -``` html - - -``` -{% raw %}
{% endraw %} - -{% raw %}
{% endraw %} -#### Good - -``` html - - -``` - -``` html - - -``` -{% raw %}
{% endraw %} - - - -### Component name casing in templates strongly recommended - -**In most projects, component names should always be PascalCase in [single-file components](../guide/single-file-components.html) and string templates - but kebab-case in DOM templates.** - -PascalCase has a few advantages over kebab-case: - -- Editors can autocomplete component names in templates, because PascalCase is also used in JavaScript. -- `` is more visually distinct from a single-word HTML element than ``, because there are two character differences (the two capitals), rather than just one (a hyphen). -- If you use any non-Vue custom elements in your templates, such as a web component, PascalCase ensures that your Vue components remain distinctly visible. - -Unfortunately, due to HTML's case insensitivity, DOM templates must still use kebab-case. - -Also note that if you've already invested heavily in kebab-case, consistency with HTML conventions and being able to use the same casing across all your projects may be more important than the advantages listed above. In those cases, **using kebab-case everywhere is also acceptable.** - -{% raw %}
{% endraw %} -#### Bad - -``` html - - -``` - -``` html - - -``` - -``` html - - -``` -{% raw %}
{% endraw %} - -{% raw %}
{% endraw %} -#### Good - -``` html - - -``` - -``` html - - -``` - -OR - -``` html - - -``` -{% raw %}
{% endraw %} - - - -### Component name casing in JS/JSX strongly recommended - -**Component names in JS/[JSX](../guide/render-function.html#JSX) should always be PascalCase, though they may be kebab-case inside strings for simpler applications that only use global component registration through `Vue.component`.** - -{% raw %} -
- -

Detailed Explanation

-
-{% endraw %} - -In JavaScript, PascalCase is the convention for classes and prototype constructors - essentially, anything that can have distinct instances. Vue components also have instances, so it makes sense to also use PascalCase. As an added benefit, using PascalCase within JSX (and templates) allows readers of the code to more easily distinguish between components and HTML elements. - -However, for applications that use **only** global component definitions via `Vue.component`, we recommend kebab-case instead. The reasons are: - -- It's rare that global components are ever referenced in JavaScript, so following a convention for JavaScript makes less sense. -- These applications always include many in-DOM templates, where [kebab-case **must** be used](#Component-name-casing-in-templates-strongly-recommended). - -{% raw %}
{% endraw %} - -{% raw %}
{% endraw %} -#### Bad - -``` js -Vue.component('myComponent', { - // ... -}) -``` - -``` js -import myComponent from './MyComponent.vue' -``` - -``` js -export default { - name: 'myComponent', - // ... -} -``` - -``` js -export default { - name: 'my-component', - // ... -} +``` html +
    +
  • + {{ todo.text }} +
  • +
``` {% raw %}
{% endraw %} {% raw %}
{% endraw %} #### Good -``` js -Vue.component('MyComponent', { - // ... -}) -``` - -``` js -Vue.component('my-component', { - // ... -}) -``` - -``` js -import MyComponent from './MyComponent.vue' -``` - -``` js -export default { - name: 'MyComponent', - // ... -} +``` html +
    +
  • + {{ todo.text }} +
  • +
``` {% raw %}
{% endraw %} +### AVOID `v-if` with `v-for` +Never use `v-if` on the same element as `v-for`. There are two common cases where this can be tempting: -### Full-word component names strongly recommended +- To filter items in a list (e.g. `v-for="user in users" v-if="user.isActive"`). In these cases, replace `users` with a new computed property that returns your filtered list (e.g. `activeUsers`). -**Component names should prefer full words over abbreviations.** +- To avoid rendering a list if it should be hidden (e.g. `v-for="user in users" v-if="shouldShowUsers"`). In these cases, move the `v-if` to a container element (e.g. `ul`, `ol`). -The autocompletion in editors make the cost of writing longer names very low, while the clarity they provide is invaluable. Uncommon abbreviations, in particular, should always be avoided. +{% raw %} +
+ +

Detailed Explanation

+
+{% endraw %} -{% raw %}
{% endraw %} -#### Bad +When Vue processes directives, `v-for` has a higher priority than `v-if`, so that this template: +``` html +
    +
  • + {{ user.name }} +
  • +
``` -components/ -|- SdSettings.vue -|- UProfOpts.vue -``` -{% raw %}
{% endraw %} -{% raw %}
{% endraw %} -#### Good +Will be evaluated similar to: +``` js +this.users.map(function (user) { + if (user.isActive) { + return user.name + } +}) ``` -components/ -|- StudentDashboardSettings.vue -|- UserProfileOptions.vue -``` -{% raw %}
{% endraw %} - - -### Prop name casing strongly recommended - -**Prop names should always use camelCase during declaration, but kebab-case in templates and [JSX](../guide/render-function.html#JSX).** - -We're simply following the conventions of each language. Within JavaScript, camelCase is more natural. Within HTML, kebab-case is. +So even if we only render elements for a small fraction of users, we have to iterate over the entire list every time we re-render, whether or not the set of active users has changed. -{% raw %}
{% endraw %} -#### Bad +By iterating over a computed property instead, like this: ``` js -props: { - 'greeting-text': String +computed: { + activeUsers: function () { + return this.users.filter(function (user) { + return user.isActive + }) + } } ``` -{% codeblock lang:html %} - -{% endcodeblock %} -{% raw %}
{% endraw %} +``` html +
    +
  • + {{ user.name }} +
  • +
+``` -{% raw %}
{% endraw %} -#### Good +We get the following benefits: -``` js -props: { - greetingText: String -} -``` +- The filtered list will _only_ be re-evaluated if there are relevant changes to the `users` array, making filtering much more efficient. +- Using `v-for="user in activeUsers"`, we _only_ iterate over active users during render, making rendering much more efficient. +- Logic is now decoupled from the presentation layer, making maintenance (change/extension of logic) much easier. -{% codeblock lang:html %} - -{% endcodeblock %} -{% raw %}
{% endraw %} +We get similar benefits from updating: +``` html +
    +
  • + {{ user.name }} +
  • +
+``` +to: -### Multi-attribute elements strongly recommended +``` html +
    +
  • + {{ user.name }} +
  • +
+``` -**Elements with multiple attributes should span multiple lines, with one attribute per line.** +By moving the `v-if` to a container element, we're no longer checking `shouldShowUsers` for _every_ user in the list. Instead, we check it once and don't even evaluate the `v-for` if `shouldShowUsers` is false. -In JavaScript, splitting objects with multiple properties over multiple lines is widely considered a good convention, because it's much easier to read. Our templates and [JSX](../guide/render-function.html#JSX) deserve the same consideration. +{% raw %}
{% endraw %} {% raw %}
{% endraw %} #### Bad ``` html -Vue Logo +
    +
  • + {{ user.name }} +
  • +
``` ``` html - +
    +
  • + {{ user.name }} +
  • +
``` {% raw %}
{% endraw %} @@ -1277,38 +737,44 @@ In JavaScript, splitting objects with multiple properties over multiple lines is #### Good ``` html -Vue Logo +
    +
  • + {{ user.name }} +
  • +
``` ``` html - +
    +
  • + {{ user.name }} +
  • +
``` {% raw %}
{% endraw %} +### CONSIDER using `v-if`/`v-else-if`/`v-else` with `key` on elements of the same type +It's usually best to use `key` with `v-if` + `v-else`, if they are the same element type (e.g. both `
` elements). -### Simple expressions in templates strongly recommended - -**Component templates should only include simple expressions, with more complex expressions refactored into computed properties or methods.** - -Complex expressions in your templates make them less declarative. We should strive to describe _what_ should appear, not _how_ we're computing that value. Computed properties and methods also allow the code to be reused. +By default, Vue updates the DOM as efficiently as possible. That means when switching between elements of the same type, it simply patches the existing element, rather than removing it and adding a new one in its place. This can have [unintended consequences](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-priority-d-rules-unintended-consequences) if these elements should not actually be considered the same. {% raw %}
{% endraw %} #### Bad ``` html -{{ - fullName.split(' ').map(function (word) { - return word[0].toUpperCase() + word.slice(1) - }).join(' ') -}} +
+ Error: {{ error }} +
+
+ {{ results }} +
``` {% raw %}
{% endraw %} @@ -1316,92 +782,95 @@ Complex expressions in your templates make them less declarative. We should stri #### Good ``` html - -{{ normalizedFullName }} -``` - -``` js -// The complex expression has been moved to a computed property -computed: { - normalizedFullName: function () { - return this.fullName.split(' ').map(function (word) { - return word[0].toUpperCase() + word.slice(1) - }).join(' ') - } -} +
+ Error: {{ error }} +
+
+ {{ results }} +
``` {% raw %}
{% endraw %} +### PREFER self-closing component tags +Component tags with no content should be self-closing in [single-file components](../guide/single-file-components.html), string templates, and [JSX](../guide/render-function.html#JSX) - but never in DOM templates. -### Simple computed properties strongly recommended - -**Complex computed properties should be split into as many simpler properties as possible.** - -{% raw %} -
- -

Detailed Explanation

-
-{% endraw %} +Self-closing component tags communicate that they not only have no content, but are **meant** to have no content. It's the difference between a blank page in a book and one labeled "This page intentionally left blank." Your code is also cleaner without the unnecessary closing tag. -Simpler, well-named computed properties are: +Unfortunately, HTML doesn't allow custom elements to be self-closing - only [official "void" elements](https://www.w3.org/TR/html/syntax.html#void-elements). That's why the strategy is only possible when Vue's template compiler can reach the template before the DOM, then serve the DOM spec-compliant HTML. -- __Easier to test__ +{% raw %}
{% endraw %} +#### Bad - When each computed property contains only a very simple expression, with very few dependencies, it's much easier to write tests confirming that it works correctly. +``` html + + +``` -- __Easier to read__ +``` html + + +``` +{% raw %}
{% endraw %} - Simplifying computed properties forces you to give each value a descriptive name, even if it's not reused. This makes it much easier for other developers (and future you) to focus on the code they care about and figure out what's going on. +{% raw %}
{% endraw %} +#### Good -- __More adaptable to changing requirements__ +``` html + + +``` - Any value that can be named might be useful to the view. For example, we might decide to display a message telling the user how much money they saved. We might also decide to calculate sales tax, but perhaps display it separately, rather than as part of the final price. +``` html + + +``` +{% raw %}
{% endraw %} - Small, focused computed properties make fewer assumptions about how information will be used, so require less refactoring as requirements change. +### PREFER putting each element attribute on its own line -{% raw %}
{% endraw %} +In JavaScript, splitting objects with multiple properties over multiple lines is widely considered a good convention, because it's much easier to read. Our templates and [JSX](../guide/render-function.html#JSX) deserve the same consideration: Elements with multiple attributes should span multiple lines, with one attribute per line. {% raw %}
{% endraw %} #### Bad -``` js -computed: { - price: function () { - var basePrice = this.manufactureCost / (1 - this.profitMargin) - return ( - basePrice - - basePrice * (this.discountPercent || 0) - ) - } -} +``` html +Vue Logo +``` + +``` html + ``` {% raw %}
{% endraw %} {% raw %}
{% endraw %} #### Good -``` js -computed: { - basePrice: function () { - return this.manufactureCost / (1 - this.profitMargin) - }, - discount: function () { - return this.basePrice * (this.discountPercent || 0) - }, - finalPrice: function () { - return this.basePrice - this.discount - } -} +``` html +Vue Logo ``` -{% raw %}
{% endraw %} - +``` html + +``` +{% raw %}{% endraw %} -### Quoted attribute values strongly recommended +### DO quote attribute values -**Non-empty HTML attribute values should always be inside quotes (single or double, whichever is not used in JS).** +Non-empty HTML attribute values should always be inside quotes (single or double, whichever is not used in JS). While attribute values without any spaces are not required to have quotes in HTML, this practice often leads to _avoiding_ spaces, making attribute values less readable. @@ -1429,11 +898,9 @@ While attribute values without any spaces are not required to have quotes in HTM ``` {% raw %}{% endraw %} +### DO have a consistent usage strategy for directive shorthands - -### Directive shorthands strongly recommended - -**Directive shorthands (`:` for `v-bind:`, `@` for `v-on:` and `#` for `v-slot`) should be used always or never.** +Directive shorthands (`:` for `v-bind:`, `@` for `v-on:` and `#` for `v-slot`) should be used either _always_ or _never_. {% raw %}
{% endraw %} #### Bad @@ -1516,76 +983,160 @@ While attribute values without any spaces are not required to have quotes in HTM {% raw %}
{% endraw %} +## Styles +### PREFER using scoped styles over global -## Priority C Rules: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead) +For applications, styles in a top-level `App` component and in layout components may be global, but all other components should always be scoped. +This is only relevant for [single-file components](../guide/single-file-components.html). It does _not_ require that the [`scoped` attribute](https://vue-loader.vuejs.org/en/features/scoped-css.html) be used. Scoping could be through [CSS modules](https://vue-loader.vuejs.org/en/features/css-modules.html), a class-based strategy such as [BEM](http://getbem.com/), or another library/convention. +**Component libraries, however, should prefer a class-based strategy instead of using the `scoped` attribute.** -### Component/instance options order recommended +This makes overriding internal styles easier, with human-readable class names that don't have too high specificity, but are still very unlikely to result in a conflict. -**Component/instance options should be ordered consistently.** +{% raw %} +
+ +

Detailed Explanation

+
+{% endraw %} -This is the default order we recommend for component options. They're split into categories, so you'll know where to add new properties from plugins. +If you are developing a large project, working with other developers, or sometimes include 3rd-party HTML/CSS (e.g. from Auth0), consistent scoping will ensure that your styles only apply to the components they are meant for. -1. **Side Effects** (triggers effects outside the component) - - `el` +Beyond the `scoped` attribute, using unique class names can help ensure that 3rd-party CSS does not apply to your own HTML. For example, many projects use the `button`, `btn`, or `icon` class names, so even if not using a strategy such as BEM, adding an app-specific and/or component-specific prefix (e.g. `ButtonClose-icon`) can provide some protection. -2. **Global Awareness** (requires knowledge beyond the component) - - `name` - - `parent` +{% raw %}
{% endraw %} -3. **Component Type** (changes the type of the component) - - `functional` +{% raw %}
{% endraw %} +#### Bad -4. **Template Modifiers** (changes the way templates are compiled) - - `delimiters` - - `comments` +``` html + -5. **Template Dependencies** (assets used in the template) - - `components` - - `directives` - - `filters` + +``` +{% raw %}
{% endraw %} -6. **Composition** (merges properties into the options) - - `extends` - - `mixins` +{% raw %}
{% endraw %} +#### Good -7. **Interface** (the interface to the component) - - `inheritAttrs` - - `model` - - `props`/`propsData` +``` html + -8. **Local State** (local reactive properties) - - `data` - - `computed` + + +``` -10. **Non-Reactive Properties** (instance properties independent of the reactivity system) - - `methods` +``` html + -11. **Rendering** (the declarative description of the component output) - - `template`/`render` - - `renderError` + + +``` + +``` html + + + + +``` +{% raw %}
{% endraw %} + + + +### PREFER class over element selectors with `scoped` styles + +Prefer class selectors over element selectors in `scoped` styles, because large numbers of element selectors are slow. +{% raw %} +
+ +

Detailed Explanation

+
+{% endraw %} + +To scope styles, Vue adds a unique attribute to component elements, such as `data-v-f3f3eg9`. Then selectors are modified so that only matching elements with this attribute are selected (e.g. `button[data-v-f3f3eg9]`). + +The problem is that large numbers of [element-attribute selectors](http://stevesouders.com/efws/css-selectors/csscreate.php?n=1000&sel=a%5Bhref%5D&body=background%3A+%23CFD&ne=1000) (e.g. `button[data-v-f3f3eg9]`) will be considerably slower than [class-attribute selectors](http://stevesouders.com/efws/css-selectors/csscreate.php?n=1000&sel=.class%5Bhref%5D&body=background%3A+%23CFD&ne=1000) (e.g. `.btn-close[data-v-f3f3eg9]`), so class selectors should be preferred whenever possible. + +{% raw %}
{% endraw %} + +{% raw %}
{% endraw %} +#### Bad + +``` html + + + +``` +{% raw %}
{% endraw %} + +{% raw %}
{% endraw %} +#### Good + +``` html + + + +``` +{% raw %}
{% endraw %} -### Element attribute order recommended +## Ordering -**The attributes of elements (including components) should be ordered consistently.** +### CONSIDER having a consistent order for element attributes This is the default order we recommend for component options. They're split into categories, so you'll know where to add custom attributes and directives. @@ -1625,75 +1176,66 @@ This is the default order we recommend for component options. They're split into - `v-html` - `v-text` +### CONSIDER having a consistent order for component/instance options +This is the default order we recommend for component options. They're split into categories, so you'll know where to add new properties from plugins. -### Empty lines in component/instance options recommended - -**You may want to add one empty line between multi-line properties, particularly if the options can no longer fit on your screen without scrolling.** +1. **Side Effects** (triggers effects outside the component) + - `el` -When components begin to feel cramped or difficult to read, adding spaces between multi-line properties can make them easier to skim again. In some editors, such as Vim, formatting options like this can also make them easier to navigate with the keyboard. +2. **Global Awareness** (requires knowledge beyond the component) + - `name` + - `parent` -{% raw %}
{% endraw %} -#### Good +3. **Component Type** (changes the type of the component) + - `functional` -``` js -props: { - value: { - type: String, - required: true - }, +4. **Template Modifiers** (changes the way templates are compiled) + - `delimiters` + - `comments` - focused: { - type: Boolean, - default: false - }, +5. **Template Dependencies** (assets used in the template) + - `components` + - `directives` + - `filters` - label: String, - icon: String -}, +6. **Composition** (merges properties into the options) + - `extends` + - `mixins` -computed: { - formattedValue: function () { - // ... - }, +7. **Interface** (the interface to the component) + - `inheritAttrs` + - `model` + - `props`/`propsData` - inputClasses: function () { - // ... - } -} -``` +8. **Local State** (local reactive properties) + - `data` + - `computed` -``` js -// No spaces are also fine, as long as the component -// is still easy to read and navigate. -props: { - value: { - type: String, - required: true - }, - focused: { - type: Boolean, - default: false - }, - label: String, - icon: String -}, -computed: { - formattedValue: function () { - // ... - }, - inputClasses: function () { - // ... - } -} -``` -{% raw %}
{% endraw %} +9. **Events** (callbacks triggered by reactive events) + - `watch` + - Lifecycle Events (in the order they are called) + - `beforeCreate` + - `created` + - `beforeMount` + - `mounted` + - `beforeUpdate` + - `updated` + - `activated` + - `deactivated` + - `beforeDestroy` + - `destroyed` +10. **Non-Reactive Properties** (instance properties independent of the reactivity system) + - `methods` +11. **Rendering** (the declarative description of the component output) + - `template`/`render` + - `renderError` -### Single-file component top-level element order recommended +### CONSIDER having a consistent order for top-level elements in single-file components -**[Single-file components](../guide/single-file-components.html) should always order ` {% endraw %} + + +## Miscellaneous +### PREFER putting each component in its own file + +Whenever a build system is available to concatenate files, each component should be in its own file. This helps you to more quickly find a component when you need to edit it or review how to use it. + +{% raw %}
{% endraw %} +#### Bad + +``` js +Vue.component('TodoList', { + // ... +}) + +Vue.component('TodoItem', { + // ... +}) +``` +{% raw %}
{% endraw %} + +{% raw %}
{% endraw %} +#### Good + +``` +components/ +|- TodoList.js +|- TodoItem.js +``` + +``` +components/ +|- TodoList.vue +|- TodoItem.vue +``` +{% raw %}
{% endraw %} + +### CONSIDER adding an empty line between multi-line properties + +**You may want to add one empty line between multi-line properties, particularly if the options can no longer fit on your screen without scrolling.** + +When components begin to feel cramped or difficult to read, adding spaces between multi-line properties can make them easier to skim again. In some editors, such as Vim, formatting options like this can also make them easier to navigate with the keyboard. + +{% raw %}
{% endraw %} +#### Good + +``` js +props: { + value: { + type: String, + required: true + }, + + focused: { + type: Boolean, + default: false + }, + + label: String, + icon: String +}, + +computed: { + formattedValue: function () { + // ... + }, + + inputClasses: function () { + // ... + } +} +``` + +``` js +// No spaces are also fine, as long as the component +// is still easy to read and navigate. +props: { + value: { + type: String, + required: true + }, + focused: { + type: Boolean, + default: false + }, + label: String, + icon: String +}, +computed: { + formattedValue: function () { + // ... + }, + inputClasses: function () { + // ... + } +} +``` +{% raw %}
{% endraw %}