Skip to content
← All questions
Beginner

What is the difference between props and state in Vue?

ComponentsReactivity

Props are data passed down from a parent component. State (local reactive data) is data the component owns and manages itself. The key difference: props are read-only, state is read-write. State is declared with ref or reactive.

vue
<!-- Parent.vue -->
<template>
  <UserCard :name="userName" :role="userRole" />
</template>

<script setup>
import { ref } from 'vue'
const userName = ref('Ana')
const userRole = ref('Developer')
</script>
vue
<!-- UserCard.vue -->
<script setup>
// Props: received from parent, read-only
const props = defineProps<{
  name: string
  role: string
}>()

// State: owned by this component, read-write
const isExpanded = ref(false)
</script>

<template>
  <div>
    <h2>{{ name }} ({{ role }})</h2>
    <button @click="isExpanded = !isExpanded">
      {{ isExpanded ? 'Collapse' : 'Expand' }}
    </button>
    <p v-if="isExpanded">Profile details here...</p>
  </div>
</template>

Side by side

PropsState
Who controls itParentThe component itself
MutableNo (read-only)Yes
Declared withdefinePropsref() / reactive()
Data flowParent to child (one-way)Internal
Triggers re-renderYes, when parent changes the valueYes, when the component changes it

Why props are read-only

Vue enforces one-way data flow. If a child could modify its props, the parent's state would change without the parent knowing, making data flow unpredictable and bugs hard to trace.

ts
// This triggers a runtime warning
props.name = 'New name' // [Vue warn]: Attempting to mutate prop "name"

When you need the child to change a value the parent owns, emit an event:

vue
<!-- Child -->
<script setup>
const props = defineProps<{ count: number }>()
const emit = defineEmits<{ update: [value: number] }>()
</script>

<template>
  <button @click="emit('update', count + 1)">+1</button>
</template>

<!-- Parent -->
<Counter :count="total" @update="total = $event" />

When to use which

ScenarioUse
Configuration passed from parent (label, color, size)Props
UI toggle local to the component (open/closed, hover)State
Form input value shared with parentProps + emit (or v-model)
Data fetched inside the componentState
Data fetched by parent, displayed by childProps

See also: Can you initialize state with a prop value? · What is Vue's reactivity system?

References

Released under the MIT License.