Skip to content

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:

  1. Define props using defineProps()
  2. Access those props values within asynchronous functions or reactive logic
  3. Use props in TypeScript with proper type safety

Basic Prop Usage ​

The simplest way to define props in <script setup> is using defineProps():

vue
<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():

vue
<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:

vue
<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:

vue
<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:

vue
<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:

vue
<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>:

vue
<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>
vue
<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 ​

  1. Auto-imports: defineProps and defineEmits are automatically available in <script setup>
  2. Reactivity: Use toRefs() when destructuring props to maintain reactivity
  3. Type Safety: For TypeScript projects, use type-only declarations for better development experience
  4. 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.