`<script setup>` Is Modern Vue
setup & `<script setup>`
`<script setup>` is compile-time sugar over the setup() function — top-level bindings become available in the template automatically.
What you'll learn
- Use `<script setup>`
- Compare to setup() function form
- Mix with regular `<script>` if needed
<script setup> is the modern way to author Vue components. Anything declared at the top level — refs, functions, imports — is automatically usable in the template, with no return block needed.
<script setup> — The Modern Way
<script setup lang="ts">
import { ref } from 'vue'
const msg = ref('Hello')
const shout = () => msg.value = msg.value.toUpperCase()
</script>
<template>
<p>{{ msg }}</p>
<button @click="shout">Shout</button>
</template> The Long Form — setup()
<script setup> compiles down to a setup() function. You’d only write this form for special cases like render functions or dynamic exports.
<script lang="ts">
import { ref, defineComponent } from 'vue'
export default defineComponent({
setup() {
const msg = ref('Hello')
const shout = () => msg.value = msg.value.toUpperCase()
return { msg, shout } // explicit return
},
})
</script> The verbosity is what <script setup> removes.
Mixing With a Regular Script
You sometimes want module-level code (a non-reactive export, types, options like name). Add a second <script> block alongside the setup one:
<script lang="ts">
export default { name: 'MyComponent', inheritAttrs: false }
</script>
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
</script> Both blocks compile together; setup-block bindings remain the component’s reactive state.
Why Prefer setup
- Less boilerplate — no return statement.
- Better TS inference for props, emits, slots.
- Top-level
awaitworks. - Compile-time macros:
defineProps,defineEmits,defineModel.