Practical Usage Patterns of $attrs in Vue 3 Across Component Structures and APIs

In Vue 3, $attrs aggregates all attributes passed from a parent to a child component that are not explicitly declared via props. It replaces the separate $listeners found in Vue 2. Understanding its behavior across different component layouts and API styles is essential for flexible attribute forwarding.

Attribute Forwarding in Templates

Single Root Element

When a component has exactly one root node, any undeclared incoming attribute are automatically bound to that root element.

<!-- ParentComponent.vue -->
<template>
  <SingleRoot msg="hello" extra="value" style="color: blue;" />
</template>

<script setup>
import SingleRoot from './SingleRoot.vue';
</script>
<!-- SingleRoot.vue -->
<template>
  <div>{{ msg }}</div>
</template>

<script setup>
defineProps({ msg: String });
</script>

Here, extra and inline style are applied directly to the root <div>, turning the text blue. To access a specific undeclared attribute inside the template:

<template>
  <div>{{ $attrs.extra }}</div>
</template>

Multiple Root Elements

With more than one root node, automatic binding does not occur. Attributes must be manually assigned using v-bind.

<!-- MultiRoot.vue -->
<template>
  <section>{{ msg }}</section>
  <section v-bind="$attrs">
    {{ msg }}
  </section>
</template>

<script setup>
defineProps({ msg: String });
</script>

The second <section> receives all undeclared attributes. For selective binding:

<section :style="$attrs.style">
  {{ msg }}
</section>

This approach ensures precise control over which attributes apply to which elements.

Accessing Attributes in JavaScript

Options API

Attributes are available on the instance as this.$attrs.

<script>
export default {
  props: { msg: String },
  mounted() {
    console.log(this.$attrs);
  }
};
</script>

Composition API (Pre-3.2 Syntax)

Use the setup(props, ctx) signature; attrs resides in ctx.attrs.

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

Composition API (3.2+ Syntax with <script setup>)

Import useAttrs to retrieve the collection of undeclared attributes.

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

const definedProps = defineProps({ msg: String });
const attrCollection = useAttrs();

console.log(definedProps, attrCollection);
</script>

attrCollection behaves like a reactive object; individual entries are accessed via attrCollection.name, attrCollection.style, etc. This method aligns with the modern SFC compilation model and avoids boilerplate setup functions.

By leveraging $attrs appropriately—whether auto-bound to a sole root element, manually distributed among multiple roots, or accessed in script logic—you can build components that forward attributes transparently and maintain clean separation between declared props and passthrough data.

Tags: vue3 $attrs Component Communication Options API Composition API

Posted on Fri, 08 May 2026 01:05:36 +0000 by drexnefex