Using Props in Vue 3's <script setup>
Vue 3's Composition API introduced the <script setup>
syntax, a more concise way to write single-file components. This guide covers how to properly use props with this modern syntax.
Problem Statement
When using <script setup>
, you can't access component props the same way as in the Options API. The original question shows a common scenario where developers need to:
- Define props using
defineProps()
- Access those props values within asynchronous functions or reactive logic
- Use props in TypeScript with proper type safety
Basic Prop Usage
The simplest way to define props in <script setup>
is using defineProps()
:
<script setup>
const props = defineProps({
no: String
})
const init = async () => {
console.log(props.no) // Access props values
}
init()
</script>
Reactive Props Access
If you need to destructure props while maintaining reactivity, use toRefs()
:
<script setup>
import { defineProps, toRefs } from 'vue'
const props = defineProps({
no: String,
myIdOfSomething: Number
})
const { no, myIdOfSomething } = toRefs(props)
console.log(no.value) // Access reactive value
console.log(myIdOfSomething.value)
</script>
WARNING
Directly destructuring props without toRefs()
will break reactivity. Always use toRefs()
when you need to destructure props.
Default Values
You can define default values for props using the object syntax:
<script setup>
defineProps({
isOpen: {
type: Boolean,
default: true
}
})
</script>
TypeScript Support
Runtime Declaration
For TypeScript users, you can define props with type safety using Vue's PropType
:
<script setup lang="ts">
import { PropType } from 'vue'
defineProps({
color: {
type: String as PropType<'primary'|'info'|'success'|'error'|'warning'>,
default: 'primary'
}
})
</script>
Type-Only Declaration
For better type inference, use type-only declarations:
<script setup lang="ts">
type Color = 'primary'|'info'|'success'|'error'|'warning'
const props = defineProps<{
color: Color
disabled?: boolean
}>()
</script>
Default Values with TypeScript
Use withDefaults()
to provide default values with type-only props:
<script setup lang="ts">
interface Props {
disabled?: boolean
loading?: boolean
label?: string
}
const props = withDefaults(defineProps<Props>(), {
label: "Button Label",
loading: false,
disabled: false
})
</script>
Practical Example
Here's a complete component using props with <script setup>
:
<template>
<div class="px-4 w-8/12 sm:w-3/12">
<img :src="src" :alt="alt" class="border-none rounded-full h-auto max-w-full align-middle" />
</div>
</template>
<script setup>
const props = defineProps({
src: String,
alt: String,
})
</script>
<template>
<div class="flex flex-wrap justify-center">
<CircleImage src="/file1.jpg" alt="one" />
<CircleImage src="/file2.svg" alt="two" />
</div>
</template>
<script setup>
import CircleImage from '@/components/CircleImage.vue'
</script>
Key Points to Remember
- Auto-imports:
defineProps
anddefineEmits
are automatically available in<script setup>
- Reactivity: Use
toRefs()
when destructuring props to maintain reactivity - Type Safety: For TypeScript projects, use type-only declarations for better development experience
- Defaults: Provide default values either through object syntax or
withDefaults()
INFO
The original RFC syntax using <script setup="props, { emit }">
is outdated. Always use defineProps()
and defineEmits()
in modern Vue 3 applications.
By following these patterns, you can effectively use props in Vue 3's <script setup>
syntax while maintaining type safety, reactivity, and clean code organization.