Naming Conventions
HTML attribute names are case-insansitive, so browsers interpret uppercase characters as lowercase. When using DOM templates, camelCase prop names must be converted to kebab-case equivalents:
Vue.component('article-card', {
props: ['articleTitle'],
template: '<h3>{{ articleTitle }}</h3>'
})
Usage in templates:
<article-card article-title="Understanding Vue"></article-card>
Prop Type Definitions
Props can be defined as either a simple string array or an object with explicit types:
props: {
title: String,
viewCount: Number,
isFeatured: Boolean,
tags: Array,
metadata: Object,
onClick: Function,
asyncData: Promise
}
Using an object syntax provides documentation and generates console warnings when type mismatches occur.
Static and Dynamic Props
Static values are passed directly:
<product-card product-name="Laptop"></product-card>
Dynamic values use the v-bind directive:
<product-card v-bind:product-name="itemName"></product-card>
<product-card v-bind:product-name="item.name + ' - ' + item.brand"></product-card>
Passing Different Data Types
Numbers
Even static numbers require v-bind to be interpreted as JavaScript expressions:
<product-card v-bind:stock-count="42"></product-card>
<product-card v-bind:stock-count="availableItems"></product-card>
Booleans
<product-card in-stock></product-card>
<product-card v-bind:in-stock="false"></product-card>
<product-card v-bind:in-stock="product.available"></product-card>
Arrays
<product-card v-bind:categories="['electronics', 'computers']"></product-card>
<product-card v-bind:categories="productCategories"></product-card>
Objects
<product-card v-bind:details="{
weight: '2.5kg',
dimensions: '30x20x5cm'
}"></product-card>
<product-card v-bind:details="productInfo"></product-card>
Spreading Object Properties
To pass all properties from an object as individual props, use argumentless v-bind:
<product-card v-bind="catalogItem"></product-card>
This is equivalent to:
<product-card
v-bind:name="catalogItem.name"
v-bind:price="catalogItem.price"
v-bind:stock-count="catalogItem.stockCount"
v-bind:details="catalogItem.details"
></product-card>
One-Way Data Flow
Props create a unidirectional downward binding: parent updates flow to children, but not vice versa. This prevents accidental state mutations that would confuse data flow.
When a parent updates a prop, the child receives the latest value automatically. Modifying props directly within a child component triggers Vue warnings.
Scenario 1: Initial Value Requirement
When a prop serves as an initial value that the child needs to manage locally, copy it to a local data property:
Vue.component('counter-display', {
props: ['startValue'],
data() {
return {
count: this.startValue
}
},
template: '<span>{{ count }}</span>'
})
Scenario 2: Value Transformation
When the prop needs transformation, use a computed property:
Vue.component('text-formatter', {
props: ['inputText'],
computed: {
formattedText() {
return this.inputText.trim().toLowerCase()
}
},
template: '<p>{{ formattedText }}</p>'
})
Reference Types Warning
Objects and arrays are passed by reference. Mutating an object or array prop within a child component affects the parent state directly.
Prop Validation
Define validation rules using an object syntax with type checks, defaults, and custom validators:
Vue.component('user-profile', {
props: {
userId: Number,
username: [String, Number],
email: {
type: String,
required: true
},
tierLevel: {
type: Number,
default: 1
},
preferences: {
type: Object,
default() {
return {
theme: 'light',
language: 'en'
}
}
},
status: {
validator(value) {
return ['active', 'inactive', 'suspended'].includes(value)
}
}
}
})
Validation runs before component enstance creation, so instance properties like data or computed values aren't accessible in default or validator functions.
Type Checking with Constructors
Built-in type constructors include:
StringNumberBooleanArrayObjectDateFunctionSymbol
Custom constructors work via instanceof:
class User {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
}
Vue.component('author-card', {
props: {
creator: User
},
template: '<div>{{ creator.firstName }} {{ creator.lastName }}</div>'
})
Non-Prop Attributes
Attributes passed to a component without matching prop definitions are called non-prop attributes. These get applied to the component's root element automatically.
This accommodates third-party components with specific attribute requirements:
<date-picker data-date-format="yyyy-mm-dd"></date-picker>
Attribute Replacement and Merging
External attribute values generally replace internal ones:
// Component defines
<input type="text" class="base-input">
// Parent usage
<custom-input type="number" class="dark-theme"></custom-input>
The type attribute gets replaced, but class attributes merge intelligently: base-input dark-theme.
Disabling Attribute Inheritance
Set inheritAttrs: false to prevent automatic attribute inheritance:
Vue.component('styled-input', {
inheritAttrs: false,
props: ['label', 'modelValue'],
template: `
<label class="input-wrapper">
{{ label }}
<input
v-bind="$attrs"
v-bind:value="modelValue"
v-on:input="$emit('update:modelValue', $event.target.value)"
>
</label>
`
})
The $attrs property contains all passed attributes:
{
required: true,
placeholder: 'Enter text here',
id: 'username-input'
}
Combining inheritAttrs: false with v-bind="$attrs" gives explicit control over attribute placement. This pattern is essential for building reusable form components.
Note that inheritAttrs: false doesn't affect class and style bindings.