Skip to content

noVueMutatingProps (JavaScript)

Language JavaScript (and super languages)
biome.json
{
"linter": {
"rules": {
"nursery": {
"noVueMutatingProps": "error"
}
}
}
}

Disallow changing the props of a Vue component.

Props pass data from a parent component down to a child. The parent owns that data, so the child should treat its props as read-only. Vue refuses to assign a new value to a prop and warns about it. Changing an object or array prop in place, for example by setting one of its properties or calling push() on it, does work, but it changes the parent’s data without the parent knowing, which makes the data flow of the application hard to follow.

Instead, emit an event so the parent changes the value itself, or copy the prop into a local ref() or computed property when the child needs a value of its own.

This rule reports props that are assigned, incremented, deleted, bound with v-model, or changed in place with an array method such as push() or sort(), in the script and in the template.

<script>
export default {
props: {
count: Number,
},
methods: {
increment() {
this.count++;
},
},
};
</script>
code-block.vue:8:12 lint/nursery/noVueMutatingProps ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ This changes the prop count.

6 │ methods: {
7 │ increment() {
> 8 │ this.count++;
│ ^^^^^
9 │ },
10 │ },

ℹ A prop belongs to the parent component. Changing it from the child either fails, or changes the parent's data without the parent knowing.

ℹ Emit an event so the parent can change the value, or copy the prop into a local ref() or computed property.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

<script setup>
const props = defineProps({
items: Array,
});
function addItem() {
props.items.push("new item");
}
</script>
code-block.vue:7:9 lint/nursery/noVueMutatingProps ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ This changes the prop items.

6 │ function addItem() {
> 7 │ props.items.push("new item");
│ ^^^^^
8 │ }
9 │ </script>

ℹ A prop belongs to the parent component. Changing it from the child either fails, or changes the parent's data without the parent knowing.

ℹ Emit an event so the parent can change the value, or copy the prop into a local ref() or computed property.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

import { defineComponent } from "vue";
export default defineComponent({
props: {
user: Object,
},
setup(props) {
props.user.name = "Alice";
},
});
code-block.js:8:11 lint/nursery/noVueMutatingProps ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✖ This changes the prop user.

6 │ },
7 │ setup(props) {
> 8 │ props.user.name = "Alice";
│ ^^^^
9 │ },
10 │ });

ℹ A prop belongs to the parent component. Changing it from the child either fails, or changes the parent's data without the parent knowing.

ℹ Emit an event so the parent can change the value, or copy the prop into a local ref() or computed property.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

<script setup>
defineProps({
value: String,
});
</script>
<template>
<input v-model="value" />
</template>
<script setup>
import { ref } from "vue";
const props = defineProps({
count: Number,
});
const emit = defineEmits(["update:count"]);
const localCount = ref(props.count);
function increment() {
localCount.value++;
emit("update:count", props.count + 1);
}
</script>
<template>
<input :value="count" @input="emit('update:count', $event.target.value)" />
</template>