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>

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:

MultiRootNodeComponent.vue
1<template>
2  <label>Button Label</label>
3  <button v-bind="$attrs">Click Me</button>
4</template>

Check the official documentation for more details.

If you liked this Vue tip, follow me on X to get notified about new tips, blog posts, and more. Alternatively (or additionally), you can subscribe to my weekly Vue & Nuxt newsletter:

I will never share any of your personal data. You can unsubscribe at any time.