Vue.js Style Guide

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.

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 A Rules: Essential (Error Prevention)

Multi-word component names

Component names should always be multi-word, except for root App components, and built-in components provided by Vue, such as <transition> or <component>.

This prevents conflictsopen in new window with existing and future HTML elements, since all HTML elements are a single word.

Vue.component("todo-item", {
  // ...
});
1
2
3
export default {
  name: "TodoItem",
  // ...
};
1
2
3
4

Component data

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.

Vue.component("some-comp", {
  data: function () {
    return {
      foo: "bar",
    };
  },
});
1
2
3
4
5
6
7
// In a .vue file
export default {
  data() {
    return {
      foo: "bar",
    };
  },
};
1
2
3
4
5
6
7
8

Prop definitions

Prop definitions should be as detailed as possible.

In committed code, prop definitions should always be as detailed as possible, specifying at least type(s).

props: {
  status: String;
}
1
2
3
// Even better!
props: {
  status: {
    type: String,
    required: true,
    validator: function (value) {
      return [
        'syncing',
        'synced',
        'version-conflict',
        'error'
      ].indexOf(value) !== -1
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Keyed v-for

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.

<ul>
  <li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
</ul>
1
2
3

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:

  • 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).

  • 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).

<ul v-if="shouldShowUsers">
  <li v-for="user in users" :key="user.id">{{ user.name }}</li>
</ul>
1
2
3

Component style scoping

For applications, styles in a top-level App component and in layout components may be global, but all other components should always be scoped.

<template>
  <button class="button button-close">X</button>
</template>

<!-- Использование атрибута `scoped` -->
<style scoped>
  .button {
    border: none;
    border-radius: 2px;
  }

  .button-close {
    background-color: red;
  }
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
  <button class="c-Button c-Button--close">X</button>
</template>

<!-- Using the BEM convention -->
<style>
  .c-Button {
    border: none;
    border-radius: 2px;
  }

  .c-Button--close {
    background-color: red;
  }
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Private property names

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_).

var myGreatMixin = {
  // ...
  methods: {
    $_myGreatMixin_update: function () {
      // ...
    },
  },
};
1
2
3
4
5
6
7
8
var myGreatMixin = {
  // ...
  methods: {
    publicMethod() {
      // ...
      myPrivateFunction();
    },
  },
};

function myPrivateFunction() {
  // ...
}

export default myGreatMixin;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Component files

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.

components/
|- TodoList.vue
|- TodoItem.vue
1
2
3

Filenames of single-file componentsopen in new window should either be always PascalCase.

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.

components/
|- MyComponent.vue
1
2

Base component names

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.

components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue

1
2
3
4
5

Single-instance component names

Components that should only ever have a single active instance should begin with the The prefix, to denote that there can be only one.

components/
|- TheHeading.vue
|- TheSidebar.vue
1
2
3

Tightly coupled component names

Child components that are tightly coupled with their parent should include the parent component name as a prefix.

components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
1
2
3
4
components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue
1
2
3

Order of words in component names

Component names should start with the highest-level (often most general) words and end with descriptive modifying words.

components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue
1
2
3
4
5
6
7

Self-closing components

<!-- In single-file components, string templates, and JSX -->
<MyComponent />
1
2

Component name casing in templates

<!-- Everywhere -->
<MyComponent />
1
2

Full-word component names

Component names should prefer full words over abbreviations.

components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue
1
2
3

Prop name casing

Prop names should always use camelCase during declaration, but kebab-case in templates and JSX.

props: {
  greetingText: String;
}
1
2
3
<WelcomeMessage greeting-text="hi" />
1

Simple computed properties

Complex computed properties should be split into as many simpler properties as possible.

computed: {
  basePrice: function () {
    return this.manufactureCost / (1 - this.profitMargin)
  },
  discount: function () {
    return this.basePrice * (this.discountPercent || 0)
  },
  finalPrice: function () {
    return this.basePrice - this.discount
  }
}
1
2
3
4
5
6
7
8
9
10
11

Directive shorthands

Directive shorthands (: for v-bind:, @ for v-on: and # for v-slot) should be used always or never.

<input :value="newTodoText" :placeholder="newTodoInstructions" /><input v-bind:value="newTodoText" v-bind:placeholder="newTodoInstructions" /> 🚫
1
2
3
<input @input="onInput" @focus="onFocus" /><input v-on:input="onInput" v-on:focus="onFocus" /> 🚫
1
2
3
<template #header >
  <h1>Here might be a page title</h1>
</template>

<template v-slot:header 🚫>
  <h1>Here might be a page title</h1>
</template>
1
2
3
4
5
6
7