DEV Community

Cover image for Follow best rules while coding in Vue.js Projects
⚡ Nirazan Basnet ⚡ for IntegridSolutions

Posted on • Originally published at blog.jobins.jp

Follow best rules while coding in Vue.js Projects

After several years of working on Vue.js projects, I've honed my ability to incorporate top-notch coding principles and practices for crafting clean code. By leveraging these guidelines, we can steer clear of mistakes and embrace optimal coding patterns. It's worth noting that this perspective is founded on my personal experiences, and it may not universally apply to every team or project.

In this blog, I will enumerate a selection of best practices that can significantly enhance our code-writing endeavors.

1. Make sure to use "key" when you're using "v-for."

When you're using "v-for" with components, you should always include a "key." This helps to keep the component's internal information consistent. Even when you're working with regular elements, using "key" is a good idea. It helps ensure things behave predictably, especially when dealing with animations and making sure objects stay the same.

Bad Example

<ul>
  <li v-for="list in lists">
    {{ todo.text }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

Good Example

<ul>
  <li
    v-for="list in lists"
    :key="list.id"
  >
    {{ list.text }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

2. Don't mix v-if and v-for

It's not a good idea to use v-if and v-for on the same thing. There are two situations where you might think about doing this:

If you want to show only certain items in a list (like only active users), instead of using v-if, make a new list with just the items you want to show (like activeUsers).

If you want to hide a whole list (for example, if shouldShowUsers is false), put the v-if on a container like an ul or ol instead of using it directly on the v-for loop.

Bad Example

<ul>
  <li
    v-for="user in users"
    v-if="user.isActive"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

Good Example

<ul>
  <li
    v-for="user in activeUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

<ul>
  <template v-for="user in users" :key="user.id">
    <li v-if="user.isActive">
      {{ user.name }}
    </li>
  </template>
</ul>
Enter fullscreen mode Exit fullscreen mode

3. Choose component names with multiple words.

When naming your components, it's a good practice to have names with more than one word, except for the main App component. This helps avoid any clashes with existing or future HTML elements, as HTML elements are single words.

Bad Example

<!-- in pre-compiled templates -->
<Item />

<!-- in in-DOM templates -->
<item></item>
Enter fullscreen mode Exit fullscreen mode

Good Example

<!-- in pre-compiled templates -->
<TodoItem />

<!-- in in-DOM templates -->
<todo-item></todo-item>
Enter fullscreen mode Exit fullscreen mode

4. Naming Basics for Components​

For components that handle the core design and styles unique to your app (sometimes called presentational, dumb, or pure components), it's a good practice to start their names with a particular prefix, like Base, App, or V.

Bad Example

components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
Enter fullscreen mode Exit fullscreen mode

Good Example

components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
Enter fullscreen mode Exit fullscreen mode
components/
|- AppButton.vue
|- AppTable.vue
|- AppIcon.vue
Enter fullscreen mode Exit fullscreen mode
components/
|- JButton.vue
|- JTable.vue
|- JIcon.vue
Enter fullscreen mode Exit fullscreen mode

5. How to Write Component Names in Templates​

In most projects, when you're working with Single-File Components and string templates, your component names should be written in PascalCase. However, when you're using in-DOM templates, you should use kebab-case.

Here's why PascalCase is preferred in most cases:

Editors can help you by suggesting component names because PascalCase is also used in JavaScript.

PascalCase component names, like, look more distinct from single-word HTML elements compared to because there are two noticeable differences (the two capital letters) instead of just one (a hyphen).

If you're using any non-Vue custom elements in your templates, like a web component, using PascalCase ensures that your Vue components stand out clearly.

Bad Example

<!-- In Single-File Components and string templates -->
<mycomponent/>
Enter fullscreen mode Exit fullscreen mode
<!-- In Single-File Components and string templates -->
<myComponent/>
Enter fullscreen mode Exit fullscreen mode
<!-- In in-DOM templates -->
<MyComponent></MyComponent>
Enter fullscreen mode Exit fullscreen mode

Good Example

<!-- In Single-File Components and string templates -->
<MyComponent/>
Enter fullscreen mode Exit fullscreen mode
<!-- In in-DOM templates -->
<my-component></my-component>
Enter fullscreen mode Exit fullscreen mode

6. Prop name casing​

When you declare props, always use camelCase. If you're using props in in-DOM templates, then they should be named with kebab-case. However, in Single-File Components templates and JSX, you have the flexibility to use either kebab-case or camelCase for props. It's essential to maintain consistency in your choice of casing throughout your application. In other words, if you opt for camelCase props, avoid using kebab-case ones elsewhere in your code.

Bad Example

const props = defineProps({
  'greeting-text': String
})
Enter fullscreen mode Exit fullscreen mode
// for in-DOM templates
<welcome-message greetingText="hi"></welcome-message>
Enter fullscreen mode Exit fullscreen mode

Good Example

const props = defineProps({
  greetingText: String
})
Enter fullscreen mode Exit fullscreen mode
<WelcomeMessage greeting-text="hi"/>
// or
<WelcomeMessage greetingText="hi"/>
Enter fullscreen mode Exit fullscreen mode
// for in-DOM templates
<welcome-message greeting-text="hi"></welcome-message>
Enter fullscreen mode Exit fullscreen mode

7. Keep Component Templates Simple​

When you're working on component templates, try to use simple expressions. If you find yourself using complicated expressions, it's better to move them to computed properties or methods. This keeps your templates clear and easy to understand. Instead of getting caught up in how things are calculated, you can focus on what should be shown on the screen.

Additionally, using computed properties and methods makes your code more reusable, which is a good thing for keeping your code organized and efficient.

Bad Example

{{
  fullName.split(' ').map((word) => {
    return word[0].toUpperCase() + word.slice(1)
  }).join(' ')
}}
Enter fullscreen mode Exit fullscreen mode

Good Example

<!-- In a template -->
{{ normalizedFullName }}
Enter fullscreen mode Exit fullscreen mode
// The complex expression has been moved to a computed property
const normalizedFullName = computed(() =>
  fullName.value
    .split(' ')
    .map((word) => word[0].toUpperCase() + word.slice(1))
    .join(' ')
)
Enter fullscreen mode Exit fullscreen mode

8. Using Shortcut Notations for Directives​

When you're working with directives, like v-bind, v-on, and v-slot, you can use shorthand notations like : for v-bind, @ for v-on, and # for v-slot. But here's the rule: always use them or never use them. It's about being consistent in your code. So, pick one approach and stick with it throughout your project.

Bad Example

<input
  v-bind:value="newTodoText"
  :placeholder="newTodoInstructions"
>
Enter fullscreen mode Exit fullscreen mode
<input
  v-on:input="onInput"
  @focus="onFocus"
>
Enter fullscreen mode Exit fullscreen mode
<template v-slot:header>
  <h1>Here might be a page title</h1>
</template>

<template #footer>
  <p>Here's some contact info</p>
</template>
Enter fullscreen mode Exit fullscreen mode

Good Example

<input
  :value="newTodoText"
  :placeholder="newTodoInstructions"
>
Enter fullscreen mode Exit fullscreen mode
<input
  v-bind:value="newTodoText"
  v-bind:placeholder="newTodoInstructions"
>
Enter fullscreen mode Exit fullscreen mode
<input
  @input="onInput"
  @focus="onFocus"
>
Enter fullscreen mode Exit fullscreen mode
<input
  v-on:input="onInput"
  v-on:focus="onFocus"
>
Enter fullscreen mode Exit fullscreen mode
<template v-slot:header>
  <h1>Here might be a page title</h1>
</template>

<template v-slot:footer>
  <p>Here's some contact info</p>
</template>
Enter fullscreen mode Exit fullscreen mode
<template #header>
  <h1>Here might be a page title</h1>
</template>

<template #footer>
  <p>Here's some contact info</p>
</template>
Enter fullscreen mode Exit fullscreen mode

9. Use detailed prop definitions​

When you're writing code that involves props (which are like special instructions you can give to a component), always be as clear as you can about what those props should be like. At the very least, make sure to say what type of data the props should be. This helps everyone understand how to use your code properly and avoids any confusion.

Bad Example

// This is only OK when prototyping
const props = defineProps(['status'])
Enter fullscreen mode Exit fullscreen mode

Good Example

const props = defineProps({
  status: String
})
Enter fullscreen mode Exit fullscreen mode
const props = defineProps({
  status: {
    type: String,
    required: true,

    validator: (value) => {
      return ['syncing', 'synced', 'version-conflict', 'error'].includes(
        value
      )
    }
  }
})
Enter fullscreen mode Exit fullscreen mode

10. Connect Child Components to Parents

When you have child components that work closely with a specific parent component, it's a good idea to include the parent's name at the beginning of the child component's name. This naming strategy helps show the strong connection between them. Since files are often sorted alphabetically, it also keeps these related files grouped, making them easier to find and work with.

Bad Example

components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
Enter fullscreen mode Exit fullscreen mode
components/
|- SearchSidebar.vue
|- NavigationForSearchSidebar.vue
Enter fullscreen mode Exit fullscreen mode

Good Example

components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
Enter fullscreen mode Exit fullscreen mode
components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue
Enter fullscreen mode Exit fullscreen mode

Conclusion 🎉🎭

👏👏 I hope that by reading this far, now you can maintain a well-organized and clear Vue.js codebase, and stick to consistent naming conventions and coding practices. Use PascalCase for component names, camelCase for prop declarations, and kebab-case for in-DOM template props. Keep templates simple with basic expressions and move complex logic into computed properties or methods for readability and reusability. Make parent-child component relationships evident in names when they're closely connected. Lastly, whether you opt for shorthand notations for directives or not, maintain consistency throughout your codebase for clarity. So, I encourage you to try it out and enjoy its benefits.

Please feel free to share your thoughts and opinions with me, and if you encounter any issues or have any questions, don't hesitate to leave a comment.

Keep on hacking! Happy coding! 🚀🌈

Top comments (4)

Collapse
 
amiceli profile image
amiceli

In v-if / v-for example, activeUsers is a computed I think ?

Collapse
 
nirazanbasnet profile image
⚡ Nirazan Basnet ⚡

We may not always calculate the data, making the computed property optional. And thank you for responding :)

Collapse
 
amiceli profile image
amiceli

Maybe, for me it's best solution.
I prefer a v-for on a computed property instead a template with a v-if like v-if="user.isActive" in second good example.

I don't know what is better in performance ;)

Thread Thread
 
nirazanbasnet profile image
⚡ Nirazan Basnet ⚡

Great I will also try doing computed on such situations