An Introduction to Vue Components

Jun 6, 2019

Components are essentially custom HTML elements. They allow you to break your app down into understandable and reusable chunks, rather than having a single monolithic app. In this tutorial, you'll learn:

Creating a Component

To create a component, you should call the Vue.component() function. The Vue.component() function takes 2 parameters: a unique string id for the component, and the object definition of the component.

Suppose you have a component whose id is hello. Whenever you include an element <hello></hello> in a Vue template, Vue will replace the element with your component's template. Below is an example of a component hello with a template that displays a message in an <h1> tag.

const helloComponent = Vue.component('hello', {
  template: '<h1>Hello, World</h1>'
});
// Technically, a component is a function
typeof helloComponent; // 'function'
helloComponent.name; // 'VueComponent'

// Internally, Vue keeps a map from ids to components in
// `Vue.options.components`
Vue.options.components['hello'] === helloComponent; // true

// Renders "<h1>Hello, World</h1>"
const app = new Vue({
  template: '<hello></hello>'
});
app.$mount('#content');

Internal State With Components

One advantage Vue has over React is two way data binding on form elements. Forms in Vue are trivial using v-model, but they require a bit more work with React.

Suppose you wanted to extend the hello component with an input, so the user can enter their name. You should add a data function to your component definition that returns the initial state of the component. Make sure you define an initial state for all the properties you want Vue to watch, even if it is null.

Vue.component('hello', {
  data: () => ({
    name: 'World'
  }),
  template: `
    <div>
      <div>
        <input v-model="name"></input>
      </div>
      <h1>Hello, {{name}}</h1>
    </div>
  `
});

// Displays "Hello, World" initially, changes based on input
const app = new Vue({
  template: '<hello></hello>'
});
app.$mount('#content');

Here's how the component looks in action. You can also see a live example here.

Component Props

Suppose that, instead of having one component that handles both user input and displaying data, you want to have separate components. The top-level app template will display the <input>, and the hello component will be responsible for displaying the value of the <input>.

The way to pass data to the hello component is using props. The v-bind:name="name" binds the value of name in the hello component's template to the value of name in the top-level app state.

// `props` is an array of prop names this component accepts. If you
// don't explicitly list a prop in `props`, you won't be able to use
// it in your template.
Vue.component('hello', {
  props: ['name'],
  template: '<h1>Hello, {{name}}</h1>'
});

// The app tracks `name` as internal state, and there's an input to
// modify `name` using `v-model`. Then, `v-bind:name` passes `name` as
// a prop to the `hello` component.
const app = new Vue({
  data: () => ({ name: 'World' }),
  template: `
    <div>
      <div>
        <input v-model="name"></input>
      </div>
      <hello v-bind:name="name"></hello>
    </div>
  `
});

Here's a live example of the props-based hello component.

$emit()

Props let you pass data into a component from a parent component. The $emit() function lets you pass data from a component back to its parent, usually in response to an event.

Suppose you wanted to define a separate input-name component that allowed the user to input their name. When the user clicks the 'Update' button, your app updates the user's name and updates the <h1> tag. Here's how this works in Vue:

Vue.component('input-name', {
  data: () => ({ name: 'World' }),
  // When you click the "Update" button, Vue will emit an event `update`
  // to the parent, with the current state of 'name'.
  template: `
    <div>
      <input type="text" v-model="name">
      <button v-on:click="$emit('update', name)">
        Update
      </button>
    </div>
  `
});

const app = new Vue({
  data: () => ({ name: 'World' }),
  // To listen to the 'update' event, you create the `input-name`
  // component with a `v-on:update` attribute. `$event` contains
  // the value of the 2nd parameter to `$emit()`.
  template: `
    <div>
      <div>
        <input-name v-on:update="setName($event)"></input-name>
      </div>
      <h1>Hello, {{name}}</h1>
    </div>
  `,
  methods: {
    // Define a method that Vue will call to handle the 'update' event.
    setName: function(v) {
      this.name = v;
    }
  }
});
app.$mount('#content');

Here's a live example.


More Vue Tutorials