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.
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.
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>
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.
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.
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.
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 -
required : true
, you should not use default value. Because as it is required, the custom element must provide the value to that prop.
default : value
, the value data type must match with the data type given in the type
option.
type
option, by default property type is null. It means it can accept any type of value. You can also provide type: null
explicitily but it is the same.
type: [String, Array, Number]
. In this case the prop can accept value of type String, Array or Number. If you provide value of data type Boolean or Object, Vue will emit error.
propE: { type: Object, default: function () { return { message: 'hello' } } },
validator
option.
propF: { validator: function (value) { return value > 10 } }
The validator function must return Boolean
. If the returned value is true
, the validation check is passed and if the false
value is returned, the validation is failed and Vue will emit error in the console.
<my-component :age="7"></my-component> Vue.component("myComponent",{ props : { age : { type : Number, required : true, validator : function(value){ return value>18; } } }, template : ` <div> Age : {{ age }} </div> `, });
Note that props are validated before a component instance is created, so within default or validator functions, instance properties such as from data, computed, or methods will not be available.
You can use these type -
String
Number
Boolean
Function
Object
Array
Symbol
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>
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>