LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 1616 min read

Props

Pass data from a parent component into a child using props, with validation and default values.

Declaring Props

A component declares the props it accepts using the defineProps compiler macro, available automatically inside <script setup> with no import needed.

<!-- ProductCard.vue -->
<script setup>
const props = defineProps(['title', 'price']);
</script>
<template>
<div class="card">
<h3>{{ title }}</h3>
<p>{{ price }}</p>
</div>
</template>

Passing Props from a Parent

A parent passes a prop exactly like an HTML attribute — as a static string, or dynamically bound with :prop to a JavaScript expression.

<script setup>
import ProductCard from './ProductCard.vue';
const product = { title: 'Wireless Mouse', price: '$24.99' };
</script>
<template>
<ProductCard title="Static Title" price="$0.00" />
<ProductCard :title="product.title" :price="product.price" />
</template>

Prop Types and Validation

For anything beyond a quick prototype, declare props with types, required flags, and default values — Vue validates these in development and warns clearly when something doesn't match.

<script setup>
const props = defineProps({
title: { type: String, required: true },
price: { type: Number, required: true },
inStock: { type: Boolean, default: true },
tags: { type: Array, default: () => [] },
});
</script>
Default Values for Objects/Arrays Need a Factory Function

default: [] would share the same array instance across every use of the component — always use default: () => [] (or () => ({})) so each instance gets its own copy.

One-Way Data Flow

Props flow only downward — from parent to child. A child must never mutate a prop directly; doing so triggers a warning, since the parent is the true owner of that data. If a child needs to change something derived from a prop, it should hold its own local reactive copy, or emit an event asking the parent to make the change.

Mutating a Prop Directly

vue
const props = defineProps(['count']);
function increment() {
props.count++; // ⚠️ Vue warns: never mutate a prop
}

Using Local State Instead

vue
const props = defineProps(['count']);
const localCount = ref(props.count);
function increment() {
localCount.value++; // fine — this is the child\'s own state
}

Common Beginner Mistakes

Mutating a prop inside the child component

This breaks one-way data flow and produces a runtime warning — emit an event instead, letting the parent decide whether and how to update its own data.

Forgetting camelCase-to-kebab-case conversion

A prop named maxCount is declared in camelCase in <script>, but passed as max-count in templates (both work due to Vue's automatic conversion, but consistency matters for readability).

FAQs

Yes — a validator field alongside type lets you write custom validation logic, e.g. checking that a value is one of a specific set of allowed strings.

Vue logs a console warning in development, but the app still runs — the prop's value will simply be undefined unless a default is also provided.

Summary

Props pass data one way, from parent to child, and should be treated as read-only inside the child. Next, you'll learn the other direction: how a child communicates back up to its parent with custom events.

Next Lesson →

Custom Events