Vue Components
Vue components let you split an interface into small, reusable pieces, each with its own template, data, and configurable props.
What a Component Is
A component is a reusable Vue instance definition - an options object with its own template, data, methods, and lifecycle hooks - that you compose together like custom HTML elements. Instead of one large monolithic template, a page becomes a tree of small, focused components that each solve one job.
Defining and Registering a Component
There are two ways to register a component. Global registration, using app.component(name, options), makes the component available in every template throughout the app. Local registration, using the components option on a parent, makes the component available only within that parent's own template.
Global registration
<div id="app">
<alert-banner message="Global registration example" />
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const app = Vue.createApp({})
app.component('alert-banner', {
props: ['message'],
template: '<p class="alert">{{ message }}</p>'
})
app.mount('#app')
</script>Local Registration
Local registration keeps a component scoped to the parent that needs it, which reduces bundle bloat in large applications and is the recommended default in most style guides. You import or define the component, then list it under the components option of whichever parent uses it.
Local registration
<div id="app">
<task-item title="Write Vue lesson" />
<task-item title="Review pull request" />
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const TaskItem = {
props: ['title'],
data() {
return { done: false }
},
template: `
<div class="task">
<input type="checkbox" v-model="done" />
<span :class="{ done: done }">{{ title }}</span>
</div>
`
}
const app = Vue.createApp({
components: {
TaskItem
}
})
app.mount('#app')
</script>- In the components option, register with PascalCase; in templates you may reference the tag as either PascalCase or kebab-case depending on your build setup.
- Every component's data option must be a function that returns a new object, so each instance keeps its own independent state.
- Props declared with the object syntax can specify type, required, and default, and Vue warns in the console if a passed value doesn't match.
- Data flows down through props in one direction only; a child component should treat its props as read-only input.
Passing Data In with Props
Props are how a parent passes data down into a child. They can be declared as a simple array of names, or as an object where each entry configures type, required, and default. Inside the child, a declared prop is read directly as this.propName. Use v-bind (the colon shorthand) whenever the value passed isn't a plain string literal.
Props with type validation and defaults
<div id="app">
<user-card name="Priya Shah" :age="29" role="Engineer" />
<user-card :name="dynamicName" :age="dynamicAge" />
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const UserCard = {
props: {
name: { type: String, required: true },
age: { type: Number, default: 18 },
role: { type: String, default: 'Member' }
},
template: `
<div class="user-card">
<h4>{{ name }}</h4>
<p>{{ role }}, age {{ age }}</p>
</div>
`
}
const app = Vue.createApp({
data() {
return {
dynamicName: 'Marco Reyes',
dynamicAge: 34
}
},
components: { UserCard }
})
app.mount('#app')
</script>Exercise: Vue Components
Why shouldn't a child component directly mutate a prop it receives?