What is Component?

Components are one of the most powerful features of Vue. They help you extend basic HTML elements to encapsulate reusable code. At a high level, components are custom elements that Vue’s compiler attaches behavior to.

All Vue components are also Vue instances, and so accept the same options object (except for a few root-specific options) and provide the same lifecycle hooks.

Basic Syntax

Vue.component(tagName, options)

			Vue.component('my-component', {
			  // options
			});
		

For example, consider the following simple example -

		<div>
			<my-heading></my-heading>
		</div>

		Vue.component('my-heading',{
			template : `
				<h1>Hello World</h1>
			`,
		});
		

If you refresh the page and inspect the DOM, the element <my-heading> is replaced with <h1>Hello World</h1>. This is simple logic, anything that is inside the template option of Vue component replces the DOM tagName. The template option can be complex as far as it could go. You can build a big component in any way you want. Throughout the tutorial we will learn about many options ane their proper usage.

Component Registration

Global Registration

A component needs to be registered before you the root el element is mounted in the DOM. In simple language, you must define your component before writting the root Vue instance.

When a Vue root instance is mounted, if Vue finds any custom component used inside the el element, Vue will replace the custom component tag name with the Component template option and will do other operation to make the component dynamic and active. That's why component definition should come before Vue start mounting the root instance. If you define your component after the root instance, during the root instance mountation, Vue will be unable to find the component definition at that time, and Vue certainly give you error in the browser console.

			<div id="example">
			  <my-component></my-component>
			</div>


			// register
			Vue.component('my-component', {
			  template: '<div>A custom component!</div>'
			})

			// create a root instance
			new Vue({
			  el: '#example'
			})
		

The above example will render the following in the DOM -

			<div id="example">
			  <div>A custom component!</div>
			</div>
		

Local Registration

If you go with the above approach Vue.component(tagname, options), this way the component is registered globally. It means you can use the component anywhere within the root instance. Also you can use it inside another component.

However what if you want to put a scope of a component so that it can only be used in a specific area. For this case, we need to define our component in different way. Here is the syntax -

			var Child = {
			  template: '<div>A custom component!</div>'
			};
		

Here we are creating a component variable which is an object and we can use all the options like we can use it in Vue.component().

Now we can make a component available only in the scope of another instance/component by registering it with the components instance option:

			new Vue({
			  // ...
			  components: {
			    // <my-component> will only be available in this component.
			    'my-component': Child
			  }
			});
		

You can use components option in multiple component to make the Child component available in multiple component. It means if you want to use this Child component in another component, all you have to do is register the component(like above) with the components options.

Data Option

Most of the options that can be passed into the Vue constructor can be used in a component, with one special case: data must be a function. In fact, if you try this:

			Vue.component('my-component', {
			  template: '<span>{{ message }}</span>',
			  data: {
			    message: 'hello'
			  }
			});
		

Then Vue will halt and emit warnings in the console, telling you that data must be a function for component instances. So instead of an object you must provide an option which returns a fresh object. Like the following -

			Vue.component('my-component', {
			  template: '<span>{{ message }}</span>',
			  data: function(){
			    return {
					message : 'hello'
				}
			  }
			});
		

One thing to remember that every property you have inside the data option is local to this component only. Only this component can use these data properties. It's parent cannot access these properties in any way or even this component cannot access it's parent's data properties. Defining a component means it's states and logic is totally seperate from the other component and even from parent.

props

Now you know that, every property is local to the component and a component cannot access it's parent componnet's property. So what if you need to use a parent component's property? The answer is props. It is similar to arguments of a method. You pass the properties to the component so that the component can have it's own copy of parent component's properties. So changing them within the component never update parent component's property. Just like method parameters.

			<div id="example">
				<my-component v-bind:name="name"></my-component>
			</div>


			Vue.component('my-component', {
			  props : ['name'],
			  template: '<span> Hello {{ name }}</span>',
			});
			new Vue({
				el : "#example",
				data : {
					name : "Santanu Bera"
				}
			});
		

In the above example, we have defined a component that takes a prop name. Now each prop can be used as attribute in the DOM. So the example element, we have my-component tag and it's attributes are the props. Anyway we are passing a dynamic value of name so we need to bind the prop using v-bind directive. You can have multiple props seperated by comma.

			<my-element prop1="value" prop2="value2" prop3="value3"></my-element>

			props : ['prop1', 'prop2', 'prop3'],
		

Each prop must be enclosed within double or single inverted comma.

Props as an Object

In the above example, we have defined props as an Array. This is the basic, limited and shortcut way. If you want to have more control over your properties you must use object way.

		props : {
			prop1 :{
				required : true,
				type : String,
			},
			prop2 :{
				required : false,
				type : String,
				default : "Default Value"		
			},
			prop3 :{
				required : true,
				type : String,
				default : "Default Value"		
			}
		},
		

There are few things or trips and tricks to remember -

You can use these type -

camelCase vs. kebab-case

We generally use camel-case for property name(myName). And it's corresponding attribute name should be in kebab-case(my-name). Like the following -

		Vue.component('child', {
			// camelCase in JavaScript
			props: ['myMessage'],
			template: '{{ myMessage }}'
		});

		<!-- kebab-case in HTML -->
		<child my-message="hello!"></child>
		

Dynamic Props

Similar to binding a normal attribute to an expression, we can also use v-bind for dynamically binding props to data on the parent. Whenever the data is updated in the parent, it will also flow down to the child:

		<div>
			<input v-model="parentMsg">
			<br>
			<child v-bind:my-message="parentMsg"></child>
		</div>
		

You can also use the shorthand syntax for v-bind:

		<child :my-message="parentMsg"></child>