Components and Props
Chapter 1's child components were static. Props make a component reusable by letting a parent pass data into it — the same concept as React props and Angular @Input. In <script setup>, props are declared with the compiler macro defineProps.
Declaring Props with defineProps
defineProps(['name', 'age']) declares the props this component accepts. It's a compiler macro — no import needed; Vue's compiler recognizes it inside <script setup>. In the template, props are used directly by name ({{ name }}), just like a local ref. In the script, they're accessed via the returned object (props.name).
Passing Props from a Parent
Import the child, then place its tag with the props as attributes. The crucial detail, carried over from v-bind in Chapter 3: name="Philip" (no colon) passes the literal string "Philip", but :age="35" (with the colon) evaluates as an expression and passes the real number 35. Forgetting the colon on a number/boolean/array prop passes a string instead — the same string-vs-expression distinction as React's quotes-vs-curly-braces and Angular's plain-vs-bracket attributes.
Typed Props with Defaults and Validation
The object form of defineProps adds type checking, a required flag, and default values — Vue warns in the console if a required prop is missing or the wrong type is passed. This is richer than React's plain props (which need PropTypes or TypeScript for the same), and comparable to Angular's typed @Input. Defaults work like Angular's, supplying a fallback when the parent omits the prop entirely.
Passing Different Data Types
Anything that isn't a plain string needs the : binding. Note also the naming convention: a prop declared as inStock (camelCase in JS) is passed as :in-stock (kebab-case in the template) — Vue maps between them automatically, the standard HTML-attribute convention. You can use camelCase in the template too, but kebab-case is the common style.
computed, or a ref initialized from the prop); to actually change the parent's data, emit an event — covered next chapter. Mutating an object/array prop's contents in place also works technically but is discouraged for the same reason: the parent loses control of its own data.
| Vue | React | Angular |
|---|---|---|
| defineProps(['name']) | Function params { name } | @Input() name |
| name="x" (string) | name="x" | name="x" |
| :age="35" (real value) | age={35} | [age]="35" |
| { type, required, default } | PropTypes / TS + defaults | Typed input + default |
Coding Challenges
Build a MovieCard component with title and year props (declared via defineProps), rendering "Title (Year)". Use it three times in a parent with three different movies, passing year as a real number.
📄 View solutionBuild a Badge component using the object form of defineProps with a text prop (String, required) and a color prop (String, default "gray"). Render it once with a custom color and once without, confirming the default applies.
📄 View solutionBuild a ProductCard component receiving title (String), price (Number), and tags (Array) props, rendering the title, price, and the tags as a list. Pass tags as a real array using the : binding.
📄 View solutionChapter 6 Quick Reference
- defineProps([...]) — declares a component's props; a compiler macro, no import needed
- Props used directly by name in the template; via
props.namein the script - name="x" passes a string; :prop="expr" passes a real value (number/boolean/array/object)
- Object form adds type, required, and default — richer than plain React props
- camelCase prop ↔ kebab-case attribute (
inStock↔:in-stock) mapped automatically - Props are read-only — flow one way; emit an event to change parent data (next chapter)
- Next chapter: emitting events with defineEmits, and v-model on components