Vue Component Props
By Flavio Copes
Learn how Vue 3 props pass data from parent to child, including defineProps, types, defaults, required props, and camelCase vs kebab-case in templates.
- Define a prop inside the component
- Accept multiple props
- Set the prop type
- Set a prop to be mandatory
- Set the default value of a prop
- Passing props to the component
Define a prop inside the component
Props are the way components accept data from the components that include them (the parent components).
A component must declare the props it expects. In a Single File Component with <script setup> you use defineProps, the usual Vue 3 style:
<template>
<p>Hi {{ name }}</p>
</template>
<script setup>
defineProps(['name'])
</script>
With the Options API:
<template>
<p>Hi {{ name }}</p>
</template>
<script>
export default {
props: ['name']
}
</script>
Or when you register a component on the app with an inline template:
import { createApp } from 'vue'
const app = createApp({})
app.component('UserName', {
props: ['name'],
template: '<p>Hi {{ name }}</p>'
})
app.mount('#app')
Accept multiple props
List every prop you expect. From here on, the defineProps snippets go inside <script setup>, and the export default ones are the Options API equivalent:
defineProps(['firstName', 'lastName'])
export default {
props: ['firstName', 'lastName']
}
Set the prop type
Use an object form to declare types:
defineProps({
firstName: String,
lastName: String
})
Valid types:
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
In development, Vue warns when the runtime type does not match.
Allow more than one type:
defineProps({
firstName: [String, Number]
})
Set a prop to be mandatory
defineProps({
firstName: {
type: String,
required: true
}
})
Set the default value of a prop
defineProps({
firstName: {
type: String,
default: 'Unknown person'
}
})
For objects and arrays, default must be a function that returns the value. Otherwise every instance of the component would share the same object:
defineProps({
name: {
type: Object,
default() {
return {
firstName: 'Unknown',
lastName: ''
}
}
}
})
Since Vue 3.5 there is a shorter way in <script setup>. You destructure the props and use a plain JavaScript default value:
const { firstName = 'Unknown person' } = defineProps(['firstName'])
firstName stays reactive, the compiler takes care of that.
You can also write a custom validator, which is handy for complex data:
defineProps({
name: {
validator(value) {
return value === 'Flavio'
}
}
})
Passing props to the component
Static string:
<UserName name="Flavio" />
From parent state, use v-bind / ::
<template>
<UserName :name="name" />
</template>
<script setup>
import { ref } from 'vue'
import UserName from './UserName.vue'
const name = ref('Flavio')
</script>
In JavaScript you declare prop names in camelCase (firstName). In the template you can write the attribute in kebab-case (first-name), like a normal HTML attribute, and Vue maps one to the other:
<UserName first-name="Flavio" last-name="Copes" />
defineProps({
firstName: String,
lastName: String
})
Inside a .vue file firstName="Flavio" works too. In a template written directly in the HTML page, kebab-case is mandatory, because the browser lowercases attribute names before Vue sees them.
Props are one-way, from parent to child. When the parent updates the prop, the child sees the new value. Do not change a prop inside the child. If the child needs a change, emit an event to the parent, or copy the value into local state. More on that in component communication.
You can use an expression when binding:
<ColorBox :colored="color === 'white'" />Want me to talk about your product? You can sponsor this site.