Vue Tip: Use Fallthrough Attributes
Michael Hoffmann
@mokkapps
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:
<template>
<button>Click Me!</button>
</template>
And a parent using this component with:
<template>
<MyButton class="large" />
</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:
<template>
<button class="btn">Click Me!</button>
</template>
Then the final rendered DOM would now become:
<button class="btn large">Click me!</button>
It's also possible to access these fallthrough attributes in the <script>
block using the useAttrs
composable:
<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
if (!attrs.type && import.meta.env.DEV) {
console.warn('Please provide a type attribute for MyButton')
}
</script>
<template>
<button class="btn">Click Me!</button>
</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:
<template>
<label>Button Label</label>
<button>Click Me</button>
</template>
A wrapper component could add attributes like class
and v-on:click
to this component:
<template>
<MultiRootNodeComponent class="anyClass" @click="doSomething" />
</template>
By default, Vue does not know where to which root node it should add the fallthrough attributes. Should they be added to the label
or to the button
root node? In this case, Vue will show a warning in the browser console:
[Vue warn]: Extraneous non-props attributes (class) were passed to component but could not be automatically inherited because component renders fragment or text root nodes.
We can work around this specific limitation by manually defining one of the root nodes to inherit the attributes applied to the component instance:
<template>
<label>Button Label</label>
<button v-bind="$attrs">Click Me</button>
</template>
Check the official documentation for more details.
If you liked this Vue tip, follow me on BlueSky to get notified about new tips, blog posts, and more. Alternatively (or additionally), you can subscribe to my weekly Vue & Nuxt newsletter :