What Causes This Warning?
This warning occurs when you use useModel() (or defineModel()) with a prop name that hasn’t been declared in your component’s props. The model needs a corresponding prop declaration.
The Problem
<script setup>
// ❌ Using useModel without declaring the prop
const count = useModel('count') // 'count' prop not declared!
</script>
The Fix
Use defineModel (Vue 3.4+)
<script setup>
// ✅ defineModel declares the prop automatically
const count = defineModel('count')
const modelValue = defineModel() // For default v-model
</script>
Declare Props Explicitly (Vue 3.3 and earlier)
<script setup>
// ✅ Declare the prop first
const props = defineProps({
count: Number
})
const emit = defineEmits(['update:count'])
// Then create a computed for two-way binding
const count = computed({
get: () => props.count,
set: (value) => emit('update:count', value)
})
</script>
Common Scenarios
Basic v-model
<!-- Parent -->
<template>
<ChildComponent v-model="value" />
</template>
<!-- Child with defineModel (Vue 3.4+) -->
<script setup>
// ✅ Automatically declares modelValue prop
const model = defineModel()
</script>
<template>
<input v-model="model" />
</template>
Named v-model
<!-- Parent -->
<template>
<ChildComponent v-model:title="title" v-model:content="content" />
</template>
<!-- Child -->
<script setup>
// ✅ Named models
const title = defineModel('title')
const content = defineModel('content')
</script>
<template>
<input v-model="title" placeholder="Title" />
<textarea v-model="content" placeholder="Content" />
</template>
With Type and Default
<script setup>
// ✅ With options
const count = defineModel('count', {
type: Number,
default: 0,
required: false
})
// ✅ TypeScript
const count = defineModel<number>('count', {
default: 0
})
</script>
Multiple Models
<script setup>
// ✅ Multiple named models
const firstName = defineModel('firstName', { type: String })
const lastName = defineModel('lastName', { type: String })
const email = defineModel('email', { type: String })
</script>
<!-- Parent usage -->
<FormComponent
v-model:first-name="user.firstName"
v-model:last-name="user.lastName"
v-model:email="user.email"
/>
Manual Implementation (Pre-Vue 3.4)
<script setup>
// For Vue < 3.4 or when you need more control
// Step 1: Declare props
const props = defineProps({
modelValue: {
type: String,
default: ''
},
count: {
type: Number,
default: 0
}
})
// Step 2: Declare emits
const emit = defineEmits(['update:modelValue', 'update:count'])
// Step 3: Create computed properties
const model = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value)
})
const countModel = computed({
get: () => props.count,
set: (value) => emit('update:count', value)
})
</script>
<template>
<input v-model="model" />
<input v-model="countModel" type="number" />
</template>
Modifiers
<script setup>
// ✅ Handle modifiers
const [model, modifiers] = defineModel({
set(value) {
if (modifiers.capitalize) {
return value.charAt(0).toUpperCase() + value.slice(1)
}
return value
}
})
</script>
<!-- Parent usage -->
<TextInput v-model.capitalize="text" />
Migration from useModel to defineModel
<!-- Old way (deprecated) -->
<script setup>
import { useModel } from 'vue'
const props = defineProps(['modelValue'])
const model = useModel(props, 'modelValue')
</script>
<!-- New way (Vue 3.4+) -->
<script setup>
const model = defineModel()
</script>
Quick Checklist
- Use
defineModel()in Vue 3.4+ (auto-declares props) - For named models:
defineModel('propName') - Add type and default options as needed
- In older Vue, manually declare props and emits
- Use computed with getter/setter for manual implementation