A few days ago I remembered a cool feature that was part of the RFCs that made it into Vue 3 and the composition API final releases when Evan You twitted this:
So I decided to share it in case you also didn't catch up with this nice feature at the time it was announced.
What is <script setup>
?
First, let's talk about how we normally implement Single Files components (SFCs) when using the Composition API
<template>
<button class="btn" @click="onClick">{{label}}</button>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const label = ref(`I'm a very dangerous button`);
function onClick() {
label.value = `Don't touch me`
}
return {
label,
onClick
}
}
}
</script>
<style>
.btn {
outline: none;
border: none;
background: #5EDCAE;
padding: 15px;
border-radius: 5px;
color: white;
font-weight:600;
}
</style>
Here we have a very dangerous button that is ready to kick some as** at the best Cobra Kai style.
Sorry, I really liked the GIF 😅. As you see in the code above we are using the setup method to define the label and a default function when the user clicks our component and we exporting them into the <template />
to be used.
Very often setup
is the only option being used when authoring components using the Composition API and yes, one of most often complaints about it is the need to repeat all the bindings that need to be exposed to the render context.
This is where <script setup />
comes to town, with this attribute a new compile step is included where the code runs in the context of the setup()
function of the component. Applying that to our Dangerous Button:
<template>
<button class="btn" @click="onClick">{{label}}</button>
</template>
<script setup>
import { ref } from 'vue';
export const label = ref(`I'm a very dangerous button`);
function onClick() {
label.value = `Don't touch me`
}
</script>
Looks nicer right? Of course, for such a small component, it's difficult to see the benefit of this, but when components get bigger and bigger, it's appreciated.
Using setup()
arguments
What happens if we need to access the props
or the context
? Just add them as the value of the setup
attribute
<template>
<button class="btn" @click="onClick">{{label}}</button>
</template>
<script setup="props, {emit}">
import { ref } from 'vue';
export const label = ref(`I'm a very dangerous button`);
export function onClick() {
label.value = `Don't touch me`;
emit('No Mercy');
}
</script>
Declaring props or additional options
One caveat of <script setup>
is that removes the ability to declare other component options, like props
. This can be easily solved by treating the default export as additional options like this:
<script setup="props, {emit}">
import { ref } from 'vue';
export default {
props: {
color: String,
default: 'primary'
}
}
export const label = ref(`I'm a very dangerous button`);
export function onClick() {
label.value = `Don't touch me`;
emit('No Mercy');
}
export const buttonClass = computed(() => `btn-${props.color}`);
</script
Typescript
Would it work with Typescript? It should. To type setup arguments simply declare them
<script setup="props" lang="ts">
import { ref } from 'vue';
declare const props: {
color: String
}
export const label = ref(`I'm a very dangerous button`);
export function onClick() {
label.value = `Don't touch me`;
emit('No Mercy');
}
export const buttonClass = computed(() => `btn-${props.color}`);
</script
Before you go
It's important to highlight that this approach relies on the context of an SFC. script setup>
cannot be used with the src
attribute if the logic is moved to an external .js
or .ts
file.
For the sake of safety, make sure you click that 🦄 or ❤️ so we don't make our Dangerous button angrier than it currently is 😅. See ya in the comments!
Top comments (11)
Hi there, I'm getting undefined for emit as well as props when trying to import them with
<script setup="props, {emit}">
as proposed. Any hint to what could be wrong? Project was created using@vitejs/app <project-name>
... thanks!You can use
defineProps
,defineEmit
and/ordefineContext
twitter.com/watchmejizz/status/137...
Maybe update post @alvarosaburido ?
Hi dear, thanks for the amazing article, I had a problem with accessing "this" keyword properties in this new setup as it is undefined,
ex: in my previous projects i could write this.$vuetify.themes.colors.primary,
but now i can't as "this" keyword is undefined,
how to access $vuetify?
Hi there, thanks for writing. So sfc works along with the composition API, is a sugar syntax for the
setup
function so you will be not able to access $vuetify through this.Check if Vuetify already supports vue 3 and composition API vuetifyjs.com/en/introduction/road...
This syntax makes every component so clear to read, I love it!
Hey, I had no idea about that feature! Where's the official documentation about it? I dont see it mentioned in here: v3.vuejs.org/guide/composition-api...
Here it is mentioned as a Notable New Feature
how’s your IDE/plugin setup for the way of creating components? I tried with code+vetur and it’s just complaining </p>
I found an answer myself actually.
Apparently volar works?
github.com/vuejs/vitepress/pull/13...
Great little intro documents, we need more visibility into the SFC style</p>