Using script Setup for Vue 3 SFCs
Tags: vue, composition, tutorial
Published: 2021-02-03 17:33:15

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:

 {% twitter 1353796900965785602 %}

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

```javascript

<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. 

![Cobra Kai](https://media.giphy.com/media/7t4UlbMtvgTVSY3qae/giphy.gif)

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

```javascript
<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
 
```javascript
<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:

```javascript
<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

```typescript
<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!