Javascript is required
ยท
2 min read

Vue Tip: Use Fallthrough Attributes

Vue Tip: Use Fallthrough Attributes Image

A "fallthrough attribute" is an attribute or v-on event listener that is passed to a component, but is not explicitly declared in the receiving component's props or emits. Common examples of this include class, style, and id attributes.

For example, given a <MyButton> component with the following template:

MyButton.vue
1<template>
2  <button>Click Me!</button>
3</template>

And a parent using this component with:

App.vue
1<template>
2  <MyButton class="large" />
3</template>

The final rendered DOM would be:

<button class="large">Click me!</button>

If the child component's root element already has existing class or style attributes, it will be merged with the class and style values that are inherited from the parent:

MyButton.vue
1<template>
2  <button class="btn">Click Me!</button>
3</template>

Then the final rendered DOM would now become:

<button class="btn large">Click me!</button>

Warning

People can override styles of a component from outside, which should be avoided in most cases.

For example, in React, you must explicitly define a prop if you want to pass a CSS class to a child component. React does not provide an automatic attribute inheritance.

Therefore, you can disable attribute inheritance.

It's also possible to access these fallthrough attributes in the <script> block using the useAttrs composable:

MyButton.vue
1<script setup>
2import { useAttrs } from 'vue'
3const attrs = useAttrs()
4
5if (!attrs.type && import.meta.env.DEV) {
6  console.warn('Please provide a type attribute for MyButton')
7}
8</script>
9
10<template>
11  <button class="btn">Click Me!</button>
12</template>

This can be useful to add validation for the attributes. In this example, a warning is logged of the type attribute is missing on the MyButton component.

Multi Root Node

Since Vue 3, we can write components with multiple root nodes:

MultiRootNodeComponent.vue
1<template>
2  <label>Button Label</label>
3  <button>Click Me</button>
4</template>

A wrapper component could add attributes like class and v-on:click to this component:

WrapperComponent.vue
1<template>
2  <MultiRootNodeComponent class="anyClass" @click="doSomething" />
3</template>