No articles found
Try different keywords or browse our categories
Fix: defineProps is not defined in Vue.js Error
Learn how to fix the 'defineProps is not defined' error in Vue.js applications. This comprehensive guide covers Composition API, TypeScript, and best practices.
The ‘defineProps is not defined’ error is a common Vue 3 Composition API issue that occurs when trying to use defineProps without proper setup or in the wrong context. This error typically happens when using the Composition API with <script setup> or when there are issues with the build configuration.
This comprehensive guide explains what causes this error, why it happens, and provides multiple solutions to fix it in your Vue.js projects with clean code examples and directory structure.
What is the defineProps Error?
The “defineProps is not defined” error occurs when:
- Using
definePropsoutside of<script setup>context - Not using Vue 3 with Composition API
- Build tools aren’t properly configured for macro functions
- TypeScript configuration issues
- Using
definePropsin Options API components - Importing
definePropsexplicitly (which is not needed)
Common Error Messages:
defineProps is not definedReferenceError: defineProps is not definedCannot access 'defineProps' before initializationdefineProps is not a functionTypeError: defineProps is not defined
Understanding the Problem
defineProps is a compile-time macro function in Vue 3’s Composition API that’s only available within <script setup> blocks. It’s used to define props in a more concise way compared to the Options API. The error occurs when Vue’s compiler doesn’t recognize defineProps as a built-in macro function.
Typical Vue.js Project Structure:
my-vue-app/
├── package.json
├── vite.config.js
├── src/
│ ├── main.js
│ ├── App.vue
│ ├── components/
│ │ ├── ChildComponent.vue
│ │ └── ParentComponent.vue
│ ├── composables/
│ │ └── useProps.js
│ ├── assets/
│ └── styles/
│ └── main.css
└── public/
Solution 1: Use defineProps in Script Setup
The most common solution is to ensure defineProps is used within <script setup>.
❌ Without Script Setup:
<template>
<div>
<h2>{{ title }}</h2>
<p>{{ message }}</p>
</div>
</template>
<script>
// ❌ defineProps is not available here
const props = defineProps({
title: String,
message: {
type: String,
default: 'Default message'
}
})
</script>
✅ With Script Setup:
ChildComponent.vue:
<template>
<div>
<h2>{{ title }}</h2>
<p>{{ message }}</p>
</div>
</template>
<script setup>
// ✅ defineProps is available in <script setup>
const props = defineProps({
title: {
type: String,
required: true
},
message: {
type: String,
default: 'Default message'
}
})
</script>
Solution 2: Use TypeScript with defineProps
Properly configure TypeScript with defineProps for type safety.
❌ Without TypeScript Support:
<script setup>
// ❌ No type safety
const props = defineProps({
title: String,
count: Number
})
</script>
✅ With TypeScript Support:
<script setup lang="ts">
// ✅ TypeScript interface for props
interface Props {
title: string
count?: number
isActive?: boolean
}
// ✅ Type-safe props definition
const props = withDefaults(defineProps<Props>(), {
count: 0,
isActive: false
})
</script>
Solution 3: Check Vue Version Compatibility
Ensure you’re using Vue 3 with Composition API support.
❌ Vue 2 Usage:
// ❌ defineProps is not available in Vue 2
import Vue from 'vue'
export default {
// ❌ This won't work in Vue 2
setup() {
const props = defineProps(['title', 'message'])
}
}
✅ Vue 3 Usage:
<template>
<div>
<h2>{{ title }}</h2>
<p>{{ message }}</p>
</div>
</template>
<script setup>
// ✅ defineProps is available in Vue 3
const props = defineProps({
title: String,
message: String
})
</script>
Solution 4: Configure Build Tools Properly
Ensure your build tools are properly configured for Vue 3 macro functions.
❌ Without Proper Build Configuration:
// vite.config.js - ❌ Missing Vue plugin
import { defineConfig } from 'vite'
export default defineConfig({
// ❌ Missing @vitejs/plugin-vue
})
✅ With Proper Build Configuration:
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [
vue({
// ✅ Enable reactivity transform if needed
reactivityTransform: false
})
]
})
package.json:
{
"name": "my-vue-app",
"version": "1.0.0",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"dependencies": {
"vue": "^3.0.0" // ✅ Vue 3 dependency
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.0.0", // ✅ Vue plugin for Vite
"vite": "^4.0.0"
}
}
Solution 5: Use Options API Alternative
If you can’t use Composition API, use the traditional Options API.
❌ With defineProps in Options API:
<template>
<div>
<h2>{{ title }}</h2>
</div>
</template>
<script>
export default {
// ❌ defineProps doesn't work in Options API
props: defineProps(['title']) // ❌ Error
}
</script>
✅ With Options API:
<template>
<div>
<h2>{{ title }}</h2>
</div>
</template>
<script>
export default {
name: 'ChildComponent',
props: {
title: {
type: String,
required: true
},
message: {
type: String,
default: 'Default message'
}
}
}
</script>
Solution 6: Handle Complex Prop Types
Use proper syntax for complex prop definitions.
ComplexProps.vue:
<script setup lang="ts">
// ✅ Define complex prop types
interface User {
id: number
name: string
email: string
}
interface Props {
title: string
user: User
items: string[]
callback?: () => void
config?: {
theme: 'light' | 'dark'
size: 'small' | 'medium' | 'large'
}
}
const props = withDefaults(defineProps<Props>(), {
items: () => [],
config: () => ({
theme: 'light',
size: 'medium'
})
})
</script>
<template>
<div>
<h2>{{ title }}</h2>
<p>User: {{ user.name }} ({{ user.email }})</p>
<ul>
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
<p>Theme: {{ config?.theme }}, Size: {{ config?.size }}</p>
</div>
</template>
Solution 7: Use Runtime vs Compile-time Definitions
Choose between runtime and compile-time prop definitions based on your needs.
Runtime Definition (More Flexible):
<script setup>
// ✅ Runtime prop definition
const props = defineProps({
title: {
type: String,
required: true,
validator: (value: string) => value.length > 0
},
count: {
type: Number,
default: 0,
validator: (value: number) => value >= 0
}
})
</script>
Compile-time Definition (Better Type Safety):
<script setup lang="ts">
// ✅ Compile-time prop definition with TypeScript
interface Props {
title: string
count?: number
}
const props = withDefaults(defineProps<Props>(), {
count: 0
})
</script>
Working Code Examples
Complete Component with defineProps:
<template>
<div class="user-card">
<h2>{{ title }}</h2>
<div v-if="user" class="user-info">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
<p v-if="user.age" class="age">Age: {{ user.age }}</p>
</div>
<div v-else class="no-user">No user data available</div>
<div class="stats">
<p>Visits: {{ visits }}</p>
<p>Active: {{ isActive ? 'Yes' : 'No' }}</p>
</div>
<div v-if="tags && tags.length" class="tags">
<span
v-for="tag in tags"
:key="tag"
class="tag"
>
{{ tag }}
</span>
</div>
</div>
</template>
<script setup lang="ts">
interface User {
name: string
email: string
age?: number
}
interface Props {
title: string
user?: User
visits?: number
isActive?: boolean
tags?: string[]
}
// ✅ Define props with defaults
const props = withDefaults(defineProps<Props>(), {
visits: 0,
isActive: false,
tags: () => []
})
</script>
<style scoped>
.user-card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
max-width: 400px;
margin: 20px auto;
}
.user-info {
margin: 15px 0;
}
.age {
color: #666;
font-style: italic;
}
.no-user {
color: #999;
font-style: italic;
}
.stats {
margin: 15px 0;
}
.tags {
margin-top: 15px;
}
.tag {
display: inline-block;
background-color: #e9ecef;
color: #495057;
padding: 4px 8px;
border-radius: 12px;
margin-right: 5px;
font-size: 0.8em;
}
</style>
Parent Component Usage:
<template>
<div class="parent">
<h1>Parent Component</h1>
<UserCard
title="User Profile"
:user="userData"
:visits="42"
:is-active="true"
:tags="['developer', 'vue', 'javascript']"
/>
<UserCard
title="Guest Profile"
:visits="0"
:is-active="false"
/>
</div>
</template>
<script setup lang="ts">
import UserCard from './UserCard.vue'
interface User {
name: string
email: string
age?: number
}
const userData: User = {
name: 'John Doe',
email: 'john@example.com',
age: 30
}
</script>
Best Practices for defineProps
1. Always Use Script Setup
// ✅ Always use <script setup> for defineProps
<script setup>
const props = defineProps(/* ... */)
</script>
2. Use TypeScript for Type Safety
// ✅ Use TypeScript interfaces for better type safety
interface Props {
title: string
count?: number
}
3. Provide Default Values
// ✅ Use withDefaults for optional props
const props = withDefaults(defineProps<Props>(), {
count: 0
})
4. Validate Props When Needed
// ✅ Use runtime validation when needed
const props = defineProps({
title: {
type: String,
required: true,
validator: (value: string) => value.length > 0
}
})
Debugging Steps
Step 1: Check Vue Version
# Verify Vue version is 3.x
npm list vue
Step 2: Check Build Configuration
# Verify build tools are configured for Vue 3
grep -r "vue" vite.config.js
Step 3: Verify Script Setup Usage
<!-- Ensure you're using <script setup> -->
<script setup>
// defineProps should be available here
</script>
Step 4: Check TypeScript Configuration
# If using TypeScript, verify tsconfig
npx vue-tsc --noEmit
Common Mistakes to Avoid
1. Using defineProps Outside Script Setup
<!-- ❌ Don't use defineProps outside of <script setup> -->
<script>
const props = defineProps(['title']) // ❌ Error
</script>
2. Importing defineProps Explicitly
<!-- ❌ Don't import defineProps -->
<script setup>
import { defineProps } from 'vue' // ❌ Not needed
const props = defineProps(['title'])
</script>
3. Using in Vue 2 Projects
// ❌ defineProps is not available in Vue 2
import Vue from 'vue2' // ❌ Wrong version
4. Not Using Vue Plugin
// ❌ Missing Vue plugin in build configuration
export default defineConfig({
// ❌ Missing @vitejs/plugin-vue
})
Performance Considerations
1. Use Compile-time Definitions When Possible
// ✅ Compile-time definitions are more performant
interface Props {
title: string
count?: number
}
2. Avoid Complex Runtime Validation
// ❌ Avoid complex runtime validation in production
const props = defineProps({
complexObject: {
type: Object,
validator: (value) => {
// Complex validation can impact performance
return validateComplexObject(value)
}
}
})
Security Considerations
1. Validate Input Data
// ✅ Always validate prop data
const props = defineProps({
userInput: {
type: String,
validator: (value: string) => {
// Validate to prevent XSS
return typeof value === 'string' && value.length < 1000
}
}
})
2. Sanitize Prop Values
// ✅ Sanitize prop values before using
const sanitizedValue = sanitizeInput(props.userInput)
Testing Components with defineProps
1. Unit Test Prop Definitions
import { mount } from '@vue/test-utils'
import ChildComponent from '@/components/ChildComponent.vue'
describe('ChildComponent', () => {
it('should accept props correctly', () => {
const wrapper = mount(ChildComponent, {
props: {
title: 'Test Title',
message: 'Test Message'
}
})
expect(wrapper.props().title).toBe('Test Title')
expect(wrapper.props().message).toBe('Test Message')
})
it('should use default values', () => {
const wrapper = mount(ChildComponent, {
props: {
title: 'Test Title'
// message should use default
}
})
expect(wrapper.props().message).toBe('Default message')
})
})
2. Test Type Validation
it('should validate prop types', () => {
expect(() => {
mount(ChildComponent, {
props: {
title: 123 // ❌ Should be string
}
})
}).toThrow()
})
Alternative Solutions
1. Use Options API
<template>
<div>{{ title }}</div>
</template>
<script>
export default {
props: {
title: String
}
}
</script>
2. Use Composition API without defineProps
<script setup>
import { computed } from 'vue'
// ✅ Alternative approach using props parameter
export default {
props: ['title', 'message']
}
// In setup function
const setup = (props) => {
const processedTitle = computed(() => props.title.toUpperCase())
return { processedTitle }
}
</script>
Migration Checklist
- Verify Vue 3 is installed and configured
- Check that components use
<script setup> - Ensure build tools support Vue 3 macro functions
- Test prop definitions work correctly
- Verify TypeScript configuration (if using TypeScript)
- Run unit tests to confirm functionality
- Update documentation for team members
Conclusion
The ‘defineProps is not defined’ error is a common Vue 3 Composition API issue that occurs when trying to use defineProps in the wrong context or with incorrect configuration. By following the solutions provided in this guide—whether through proper <script setup> usage, correct build configuration, or TypeScript integration—you can ensure your Vue.js applications properly handle component props.
The key is to understand that defineProps is a compile-time macro function that’s only available within <script setup> blocks in Vue 3. With proper setup and configuration, your Vue.js applications will have clean, type-safe prop definitions that enhance code maintainability and developer experience.
Remember to always use Vue 3 with Composition API support, configure your build tools properly, and follow Vue’s best practices for prop definitions to create robust and maintainable components.
Related Articles
Fix: Cannot read property '$refs' of undefined in Vue.js
Learn how to fix the 'Cannot read property $refs of undefined' error in Vue.js applications. This comprehensive guide covers Vue instance access, lifecycle hooks, and best practices.
Fix: Property or method is not defined on the instance in Vue.js
Learn how to fix the 'Property or method is not defined on the instance' error in Vue.js applications. This comprehensive guide covers data properties, methods, and best practices.
How to Fix: Vue 3 emit is not defined error
Learn how to fix the 'emit is not defined' error in Vue 3 applications. This comprehensive guide covers Composition API, defineEmits, and best practices.