A Beginner’s Guide to Working With Components in Vue

Originally published at: https://www.sitepoint.com/vue-components-intro/

One of the great things about working with Vue is its component-based approach to building user interfaces. This allows you to break your application into smaller, reusable pieces (components) which you can then use to build out a more complicated structure.

In this guide, I’ll offer you a high-level introduction to working with components in Vue. I’ll look at how to create components, how to pass data between components (via both props and an event bus) and how to use Vue’s <slot> element to render additional content within a component.

Each example will be accompanied by a runnable CodePen demo.

How to Create Components in Vue

Components are essentially reusable Vue instances with a name. There are various ways to create components within a Vue application. For example, in a small- to medium-sized project you can use the Vue.component method to register a global component, like so:

Vue.component('my-counter', {
  data() {
    return {
      count: 0
    }
  },
  template: `<div>{{ count }}</div>`
})

new Vue({ el: '#app' })

The name of the component is my-counter. It can be used like so:

<div id="app">
  <my-counter></my-counter>
</div>

When naming your component, you can choose kebab case (my-custom-component) or Pascal case (MyCustomComponent). You can use either variation when referencing your component from within a template, but when referencing it directly in the DOM (as in the example above), only the kebab case tag name is valid.

You might also notice that, in the example above, data is a function which returns an object literal (as opposed to being an object literal itself). This is so that each instance of the component receives its own data object and doesn’t have to share one global instance with all other instances.

There are several ways to define a component template. Above we are using a template literal, but we could also use a <script tag> marked with text/x-template or an in-DOM template. You can read more about the different ways of defining templates here.

Single-file Components

In more complex projects, global components can quickly become unwieldy. In such cases, it makes sense to craft your application to use single-file components. As the name suggests, these are single files with a .vue extension, which contain a <template>, <script> and <style> section.

For our example above, an App component might look like this:

<template>
  <div id="app">
    <my-counter></my-counter>
  </div>
</template>

<script>
import myCounter from './components/myCounter.vue'

export default {
name: 'app',
components: { myCounter }
}
</script>

<style></style>

And a MyCounter component might look like this:

<template>
  <div>{{ count }}</div>
</template>

<script>
export default {
name: 'my-counter',
data() {
return {
count: 0
}
}
}
</script>

<style></style>

As you can see, when using single-file components, it’s possible to import and use these directly within the components where they’re needed.

In this guide, I’ll present all of the examples using the Vue.component() method of registering a component.

Using single-file components generally involves a build step (for example, with Vue CLI). If this is something you’d like to find out more about, please check out “A Beginner’s Guide to Vue CLI” in this Vue series.

Passing Data to Components Via Props

Props enable us to pass data from a parent component to child component. This makes it possible for our components to be in smaller chunks to handle specific functionalities. For example, if we have a blog component we might want to display information such as the author’s details, post details (title, body and images) and comments.

We can break these into child components, so that each component handles specific data, making the component tree look like this:

<BlogPost>
  <AuthorDetails></AuthorDetails>
  <PostDetails></PostDetails>
  <Comments></Comments>
</BlogPost>

If you’re still not convinced about the benefits of using components, take a moment to realize how useful this kind of composition can be. If you were to revisit this code in the future, it would be immediately obvious how the page is structured and where (that is, in which component) you should look for which functionality. This declarative way of composing an interface also makes it much easier for someone who isn’t familiar with a codebase to dive in and become productive quickly.

Since all the data will be passed from the parent component, it can look like this:

new Vue({
  el: '#app',
  data() {
    return {
      author: {
        name: 'John Doe',
        email: 'jdoe@example.com'
      }
    }
  }
})

In the above component, we have the author details and post information defined. Next, we have to create the child component. Let’s call the child component author-detail. So our HTML template will look like this:

<div id="app">
  <author-detail :owner="author"></author-detail>
</div>

We’re passing the child component the author object as props with the name owner. It’s important to note the difference here. In the child component, owner is the name of the prop with which we receive the data from the parent component. The data we want to receive is called author, which we’ve defined in our parent component.

To have access to this data, we need to declare the props in the author-detail component:

Vue.component('author-detail', {
  template: `
    <div>
      <h2>{{ owner.name }}</h2>
      <p>{{ owner.email }}</p>
    </div>
  ´,
  props: ['owner']
})

We can also enable validation when passing props, to make sure the right data is being passed. This is similar to PropTypes in React. To enable validation in the above example, change our component to look like this:

Vue.component('author-detail', {
  template: `
    <div>
      <h2>{{ owner.name }}</h2>
      <p>{{ owner.email }}</p>
    </div>
  `,
  props: {
    owner: {
      type: Object,
      required: true
    }
  }
})

If we pass the wrong prop type, you’ll see an error in your console that looks like what I have below:

"[Vue warn]: Invalid prop: type check failed for prop 'text'. Expected Boolean, got String.
(found in component <>)"

There’s an official guide in the Vue docs that you can use to learn about prop validation.

See the Pen Vue Componets - Props by SitePoint (@SitePoint) on CodePen.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.