Components and props

Vue · Essentials · 12 min

Components are Vue's unit of reuse and organisation; props are how parents configure them.

Each .vue file is a component. To use one, import it in <script setup> and write it as a tag, conventionally in PascalCase: <TodoItem />. No registration step is needed.

A component declares the data it accepts from its parent with props, using the defineProps compiler macro (no import needed):

const props = defineProps({
  title: { type: String, required: true },
  count: { type: Number, default: 0 },
})

With TypeScript you can write defineProps<{ title: string; count?: number }>() instead. Since Vue 3.5, destructuring props is reactive and is the idiomatic way to give defaults: const { title, count = 0 } = defineProps(...). The compiler rewrites count to props.count, so it stays reactive.

The parent passes props as attributes: static title="Inbox" or bound :count="unread" (without the colon, count="3" is the string "3"). Props declared in camelCase can be written kebab-case in templates (:max-items).

Props follow one-way data flow: when the parent's value changes the child updates, but the child must never assign to a prop. Vue warns if you try. If the child needs a local, editable copy, initialise a ref from the prop; if it wants to change the parent's data, it emits an event (next lesson).

Example

<!-- TodoItem.vue -->
<script setup>
const { text, done = false, priority = 1 } = defineProps({
  text: { type: String, required: true },
  done: Boolean,
  priority: Number,
})
</script>
<template>
  <li :class="{ done }">{{ text }} (p{{ priority }})</li>
</template>

<!-- TodoList.vue -->
<script setup>
import TodoItem from './TodoItem.vue'
const todos = [{ id: 1, text: 'Write props', done: true, priority: 2 }]
</script>
<template>
  <ul>
    <TodoItem v-for="t in todos" :key="t.id"
              :text="t.text" :done="t.done" :priority="t.priority" />
    <TodoItem text="Static text" />   <!-- done=false, priority=1 -->
  </ul>
</template>

Remember

  • Import a component in <script setup> and use it as a PascalCase tag
  • defineProps declares inputs; destructure with defaults in Vue 3.5+
  • Data flows down one way: never assign to a prop

Watch out for

  • Passing count="3" without the colon, which sends the string "3" rather than a number.

Check yourself

  1. A child component wants to change a value it received as a prop from its parent. What is the correct approach?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: vuejs.org/guide/components/props.html