Context Argument in Vue 3 Composition API Script Setup

Robin
Updated on July 12, 2022

The context argument in Vue 3 is an object that provides component functionalities. You can use composition API in 2 ways. One is using setup() function and another is using script setup syntax.

You have to access the context argument or the properties of the context argument in different ways depending on which composition API style you choose.

You will get the same result in both cases, the only difference is how we access those properties from the context object in Vue 3 Composition API.

In this article, I will show you everything in detail about the context argument why you need it, and all the arguments available in the setup() function, properties you will get inside the context object, and many more.

You will also see examples in both ways i.e. how you can use context argument in the setup() function as well as in the script setup syntax.

Why Do You Need Context Argument in Vue 3?

Earlier in Vue 2, you could only use the Options API to write your application. But in Vue 3, you can use Composition API and Options API. But there are some differences between Composition API and Options API in Vue 3.

In the Options API, you can access the this keyword inside the Vue component which represents the instance of that component. You can use the component functionalities like this.$slots, this.$emit, this.$attrs using the this keyword.

But, inside the setup() function of Composition API, you don't have access to the this keyword. Because the setup() function runs before creating the instance of a Vue component.

That's why to use those component functionalities inside the setup() function you need the context argument in Vue 3.

All Arguments in Composition API Setup Function

There are a total of 2 arguments in the setup() function. These are:

  • props
  • context

The first argument gives you access to the props that are passed to the component. The second argument is the context object.

          <script>
export default {
    setup(props, context) {
        
    }
}
</script>
        

In this post, we will only discuss the second argument and all the properties you get in the context object.

Properties Inside The Context Object in Vue 3 Setup Function

The context object has four properties. Each property gives access to a piece of component information.

These properties are:

  • context.attrs -- attribute passed to the component which is not a prop.
  • context.emit -- the function to send custom events from a component.
  • context.slots -- an object with all the template slot's render functions.
  • context.expose() -- the function to expose properties or methods for a parent component.
Vue 3 context object in composition api

These are the properties and methods available inside the context object. Let's discuss each of them in detail.

          <script>
    export default {
        setup(props, { attrs, emit, slots, expose }) {

        }
    }
</script>
        

If you don't want to call those property names using context, you can use JavaScript object destructuring instead.

Also Read: watch VS watchEffect in Vue 3 - Must Know Differences

Use of context.attrs

The context.attrs is an object that contains all the non-props attributes. If you pass any additional attribute to the component from the parent which is not defined as props, you will be able to access that attribute through this context.attrs property.

For example, I have created a component which is called MyComponent in my Vue application. This component accepts one title prop.

          // MyComponent.vue

<script>
    export default {
        props: {
            title: String
        },
        setup(props, context) {
            console.log(context.attrs.name);
        }
    }
</script>
        

Now, in the parent component when I use the MyComponent component, I can pass several attributes along with the title props.

Vue 3 context attrs object in composition api

In this example, I am passing the name attribute which is not defined as a prop. I can access the name attribute using context.attrs.name inside the MyComponent component.

          // App.vue

<template>
    <MyComponent title="Web Mound" name="my-component" />
</template>
        

The context.attrs property will contain everything other than the props. It also includes custom event listeners and HTML attributes

Note: The context.attrs property is not reactive. That means, if the value of any attribute changes, the component will not re-render. To display the updated value, you have to use the onUpdated() lifecycle hook.

Use of context.emit

The context.emit() is used to emit a custom event in the child component. It replaces the this.$emit in the options API.

You can emit your custom event with or without data. When the parent component listens to the event, it will receive that data as a payload.

          // MyComponent.vue

<template>
    <div>
        <h2>{{title}}</h2>
        <button @click="hideTitle">Hide</button>
    </div>
</template>

<script>
    export default {
        props: {
            title: String
        },
        setup(props, context) {
            const hideTitle = () => {
                context.emit('hide' /* Pass payload if any */);
            }
            
            return {
                hideTitle
            }
        }
    }
</script>
        

I am emitting an event called hide using context.emit() from the child component. When I click the button this event will be emitted.

          <template>
    <MyComponent title="Web Mound" @hide="handleEvent" />
</template>
        

When I use the MyComponent in the parent component, I will listen to the hide event using v-on directive.

Use of context.expose()

By default, all the properties and methods you return from the setup() function are accessible from the parent component. Sometime you might not want this to happen.

You can use context.expose() method to expose some properties or methods from a component. When other components use that component, they will be able to access only the exposed properties and methods.

In this way, you can isolate some functionalities within a component. Let's see an example.

          <template>
    <section>
        <h2>{{count}}</h2>
        <button @click="resetCounter">Reset</button>
        <button @click="stopCounter">Stop</button>
    </section>
</template>

<script>
import { ref } from 'vue';

export default {
    setup(props, context) {
        const count = ref(0);
        
        const timer = setInterval(() => {
            count.value++; 
        }, 1000)
        
        const resetCounter = () => {
            count.value = 0;
        }
        
        const stopCounter = () => {
            clearInterval(timer);
        }
        
        context.expose({resetCounter})
        
        return {
            count,
            resetCounter,
            stopCounter
        }
    }
}
</script>
        

In this example, I have a CountDown component that displays the count variable and updates it every second.

It also has 2 buttons. One button resets the count variable and another button stops the counter.

Inside the setup() function, I am using context.expose() method to expose the resetCounter() function. You have to pass an object in the expose() with all the properties and methods that you want to expose from a component.

          // App.vue

<template>
    <CountDown ref="counter" />
    <button @click="resetFromParent">Reset from Parent</button>
    <button @click="stopFromParent">Reset from Parent</button>
</template>

<script>
import CountDown from '../components/CountDown.vue';
import { ref } from 'vue';

export default {
    components: {MyComponent, CountDown},

    setup(props, context) {
        const counter = ref(null);
        
        const resetFromParent = () => {
            counter.value.resetCounter()
        }
        
        const stopFromParent = () => {
            counter.value.stopCounter()
        } 
        
        return {
            counter,
            resetFromParent,
            stopFromParent
        }
    }
}
</script>
        

In the App component, I am using the CountDown component. I have added a template ref to obtain a reference for the CountDown component.

Inside the setup() function, I have two functions. The resetFromParent() function calls the resetCounter() function from the CountDown component. The stopFromParent() function calls the stopCounter() function.

Vue 3 context expose function in composition api

But when I try to call the stopCounter() function, I receive an error. Because the CountDown component only exposes the resetCounter() function.

If you don't explicitly expose using the context.expose() method, App component will be able to use all the properties and methods available inside the CountDown component.

Also Read: Improve Performance in Vue 3 Using Lazy Loading and Dynamic Import

Use of context.slots

Inside the setup() function, context.slots gives you access to the render methods for slots. These methods are useful especially when we write custom render functions without using templates.

Vue always recommends using templates. Because it is easy to use. But if you want to use pure JavaScript or you have a special need to use the render function, you can create your own.

          // ShowHeading.vue

<script>
import {h} from 'vue';

export default {
    props: {
        level: Number
    },
    
    setup(props, context) {
        return () => h(
            `h${props.level}`,
            {}, // Optional: props and attributes
            context.slots.default() // Rendering default slot
        )
    }
}
</script>
        

In this example, I am creating a component with a custom render function. This component accepts one prop and displays HTML heading tags according to the prop.

Vue 3 context slots in composition api

Now you can use this ShowHeading component in other components like this:

          <template>
    <show-heading :level="2">Heading 2</show-heading>
</template>
        

The above code will show a <h2> tag in your DOM like this:

          <h2>Heading 2</h2>
        

You can give any number from 1 to 6 as the level props. Then the ShowHeading component will return a heading tag according to the number. And this component will accept the text as its default slot.

How To Use Context Properties Inside Script Setup in Vue 3

If you don't want to use setup() function in the composition API, there is another way to write your Vue 3 components.

You can use the script setup syntax instead. There are many advantages of using script setup syntax over the setup() function.

  • You get better runtime performance.
  • You can write clean code with less boilerplate.
  • You can declare your props and emit events using pure TypeScript.

That's why I always prefer to use this syntax and it is also becoming the industry standard for any Vue 3 application.

Now the question is, if you don't use the setup() function, how can you access the context properties?

Let's see how we can use all 4 context properties in the script setup syntax in Vue 3 composition API.

useAttrs() Function in Vue 3

To access attrs object in the script setup, you have to use a helper function from Vue. You can import the useAttrs() function directly from the vue package.

          <script setup>
import { useAttrs } from 'vue';

const attrs = useAttrs();

console.log(attrs);
</script>
        

When you call that helper function, it will return the attrs objects. This function is the same object that we get in the context argument.

Now, you can access any non-prop attributes from the attrs object in the script setup.

defineEmits() Function in Vue 3

To send a custom event from the script setup syntax, there is a helper function in Vue 3. The name of this function is defineEmits().

This function is automatically available inside the <script setup> syntax. You don't have to import this function from vue package.

          <script setup>
const emit = defineEmits(['hide']);

const hideTitle = () => {
    emit('hide')
}
</script>
        

You have to call the defineEmits() function with the array of event names that you want to emit for the component. This function returns another function.

Now, when you want to emit an event, you can call the emit() function with the name of the event. You can also pass any data as a payload in the second argument of the emit() function.

defineExpose() Function in Vue 3

Unlike the setup() function, the <script setup> is close by default. It means that when you define a component using script setup syntax, the parent component can not access any properties or methods from its child components.

Therefore, if you need to use any properties or methods in the parent component you have to expose those explicitly from the child component.

You have to use defineExpose() function to expose any properties or methods from a component. This function is available inside <script setup> by default. So, you don't have to import it from anywhere.

          <script setup>
import { ref } from 'vue';

const count = ref(0);

const timer = setInterval(() => {
    count.value++; 
}, 1000)

const resetCounter = () => {
    count.value = 0;
}

const stopCounter = () => {
    clearInterval(timer);
}

defineExpose({resetCounter})

</script>
        

I am calling the defineExpose() function with an object which contains all the property and method names that I want to expose from this component.

In this case, I am exposing resetCounter() function. But You can expose multiple things at once using this function.

useSlots() Function in Vue 3

To get the render methods for slots inside <script setup> in Vue 3 composition API, you have to use the useSlots() helper function.

You have to import this helper function from the vue package.

          <script setup>
import { useSlots } from 'vue';

const slots = useSlots();

console.log(slots.default());
</script>
        

When you call the useSlots() function, it will return an object. This object will contain all the render methods for slots.

Now, you can call those render methods using this object.

Conclusion

Composition API in Vue 3 has very powerful tools and gives you different ways to create your application. It also allows for writing reusable code.

The context argument is part of the composition API. Through this, you can access 4 component functionalities that are available in the options API.

In this article, we've learned about the properties of context arguments. You also have seen examples of using attrs, slots, expose, and emit in the compositions API setup() function.

You have also learned how to use those context functionalities inside <script setup> in the Vue component.

I have tried to show you everything about the context argument in Vue 3 composition API setup function along with the script setup syntax.

Related Posts