Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Props

Props are data that a parent component passes to a child through attributes. Thanks to them one TodoItem component can show any task: the text and state come from outside.

Declaring props

Create src/components/TodoItem.vue. Props are declared with the defineProps macro — it needs no import and works only inside <script setup>:

<!-- src/components/TodoItem.vue -->
<script setup>
const props = defineProps({
  todo: Object,
})
</script>
 
<template>
  <li>{{ todo.text }}</li>
</template>

The component expects a todo prop. In the template it is available by name, in the script as props.todo.

Passing from the parent

<!-- src/App.vue -->
<script setup>
import { ref } from 'vue'
import TodoItem from './components/TodoItem.vue'
 
const todos = ref([
  { id: 1, text: 'Buy bread', done: true },
  { id: 2, text: 'Call Anna', done: false },
])
</script>
 
<template>
  <ul>
    <TodoItem v-for="todo in todos" :key="todo.id" :todo="todo" />
  </ul>
</template>

The page shows a list of two tasks, each rendered by its own TodoItem instance. The colon before todo is needed to pass the object, not the string "todo".

Types and defaults

The full form describes the type, whether the prop is required and its default value:

<!-- src/components/TodoItem.vue -->
<script setup>
const props = defineProps({
  todo: {
    type: Object,
    required: true,
  },
  showDate: {
    type: Boolean,
    default: false,
  },
})
</script>

If the parent does not pass todo, the console shows the warning Missing required prop: "todo". The check runs only in development mode and helps you find the bug sooner.

TypeExample value
Stringtitle="Tasks"
Number:count="3"
Booleanshow-date (no value means true)
Array, Object:todo="todo"

Prop names

In the script props are written in camelCase (showDate), while in the parent's template the hyphenated form is customary: <TodoItem :todo="todo" show-date />. Vue matches the names itself.

Using props in the script

Since Vue 3.5 props can be destructured without losing reactivity:

<script setup>
import { computed } from 'vue'
 
const { todo, showDate = false } = defineProps({
  todo: Object,
  showDate: Boolean,
})
 
const label = computed(() => (todo.done ? '✓ ' : '') + todo.text)
</script>

label is recalculated if the parent passes a different task. In older versions such destructuring lost reactivity, which is why you often see props.todo in other people's code.

Common mistake

Changing a prop inside the child: props.todo = null or count++ on a number prop. Vue warns that the prop is read-only. The data belongs to the parent: the child should tell the parent about the desired change with an event — that is the next lesson.

Thanks for reading!

Donate to the site — we work hard for you.