Easily switch to Composition API in Vue.js 3

The fact that Vue.js 3 already reached the alpha version made me think that... it's time already for some Vue.js 3 tips!

The idea is to give you some tips related to new features you can find on Vue.js 3 as they get available. For now, we'll focus on Composition API, one of the most game-changing features!

This first one is specially focused on showing you a basic step-by-step guide or cheatsheet to migrate object-api Vue.js components to use Composition API. In future tips you'll also see how to apply certain new techniques this API allow us to do as well 😉.

I'll do that by showing you how to convert an Object-API-based component to use Composition API.

For that, let's create a MoneyCounter.vue component that basically shows a money amount and allow us to add/substract quantities to it, implemented using the following code:

    <h2>{{ formattedMoney }}</h2>
    <input v-model="delta" type="number">
    <button @click="add">Add</button>

export default {
  data: () => ({
    money: 10,
    delta: 1
  computed: {
    formattedMoney() {
      return this.money.toFixed(2);
  mounted() {
    console.log("Clock Object mounted!");
  methods: {
    add() {
      this.money += Number(this.delta);
  watch: {
    money(newVal, oldVal) {
      console.log("Money changed", newVal, oldVal);

This component has a money state which holds the quantity, the delta that is bound using v-model to the input and later used in the add method to add that quantity to money. The computed property formattedMoney correctly displays the decimal values of money. Finally, I also included a dummy watch and mounted with a console.log statement for the purpose of showing how to migrate it to Composition API.

Take some time to understand this component if you need it.

Right away, create a MoneyCounterComposition.vue component. This component shares the same <template> than the previous, since template is not affected by API's, so copy it from the previous component.

The change is in the <script> part. Let's check first how it'd be all code:

// In Vue 3, you'll import from "vue"
import { ref, computed, watch, onMounted } from "@vue/composition-api";

export default {
  setup() {
    // State
    const money = ref(10);
    const delta = ref(1);

    // Computed props
    const formattedMoney = computed(() => money.value.toFixed(2));

    // Hooks
    onMounted(() => console.log("Clock Object mounted"));

    // Methods
    const add = () => (money.value += Number(delta.value));

    // Watchers
    const moneyWatch = watch(money, (newVal, oldVal) =>
      console.log("Money changed", newVal, oldVal)

    return {

First of all, we're exporting an object with the setup function. This is required and here's where all happens. Now let's focus part by part:

State: it's implemented using ref, and as you can see you can have as many as you want. To access them you don't need to access "this", since it's just a variable not a "magic" instance thing (yay!), although to change its value you need to access the .value property. You could use reactive as well, but I encourage use to read this article from Jason Yu and use ref as a convention.

Computed: you need to use computed for it. It's basic: it takes a function as its first argument.

Hooks: every hook has its own utility. In the case of mounted hook its onMounted. Same shape as computed: they take a function as their first argument.

Methods: they're just functions, like any other. Nothing special here.

Watch: there are different signatures. That's the one equivalent to watch money, but you can check all shapes in the RFC docs.

Finally, the setup function must return an object containing everything you want to use in the template. Anything that is not there, it won't be accesible from the template.

A little note: you may notice that I'm importing from "@vue/composition-api". That's because I'm using a plugin since Vue 3 is not there yet, but with the plugin we can already use it.

I hope the following image helps you understand how to migrate this component by this side-by-side perspective:

Side to side components

If you want to see with your own eyes that this code truly works, go and check it in this CodeSandbox!

That's it for today's tip!

Don't miss out anything about Vue, your favourite framework.

Subscribe to receive all the articles we publish in a concise format, perfect for busy devs.

Related Articles

The new Provide and Inject in Vue 3

Getting stuck into the prop drilling? Learn how provide/inject can make your components more flexible and independent in this short tutorial.

Anthony Konstantinidis

Anthony Konstantinidis

Jul 18, 2022

The 101 guide to Script Setup in Vue 3

Don't you know about Script Setup yet? Check out this short article now and learn the nicest way to define a Vue component right now!

Anthony Konstantinidis

Anthony Konstantinidis

Jun 20, 2022

Going 3D with Trois.js and Vue 3

Learn about Trois.js, a JS library to render 3D scenes in Vue. In this article, we're learning the basics of using Trois.js in a Vite + Vue 3 app

Alvaro Saburido Rodriguez

Alvaro Saburido Rodriguez

Nov 16, 2021


VueDose is proudly supported by its sponsors. If you enjoy it, consider supporting it to ensure the project maintainability.

Learning Partner