How to Use Attribute Inheritance in Vue 3
Tags: webdev, vue
Published: 2023-04-23 00:09:10

by [Chris Ebube Roland](https://blog.openreplay.com/authors/chris-ebube-roland)

Attribute Inheritance, as the name implies, is when an attribute is inherited from a parent product class. In other words, it is the property by which subtype entities inherit values of all attributes and instances of all relationships of the original type. Attribute inheritance provides faster development of custom components based on HTML elements (such as custom inputs, buttons, text wrappers, or links). Attribute Inheritance was enabled in Vue 2 but became very efficient in Vue 3, with a more reliable API to use in any component. In this article, we will be talking about Attribute inheritance in Vue.3, and by the end of this tutorial, users will be able to use and disable attributes inheritance in their Vue code, understand the difference between props and non-props attributes, and how attribute inheritance affects multiple root nodes. 

## Attribute Inheritance

There are two ways to use Attribute Inheritance in Vue 3: props attributes and non-props attributes.

- Props Attributes: In Vue, props are openings within a component containing data and custom attributes that can be registered on any component. For instance, when you define your data on the parent component and give it a value, go to the child component that needs the same data and pass the value to a prop attribute. Then, automatically, the data becomes a property in the child component as well.

- Non-Props Attributes: Non-prop attributes are attributes passed to a component without a defined corresponding prop; hence, these attributes are inherited by the component. Examples are HTML attributes like `class`, `style`, or `id`.

To fully understand how to use Attribute Inheritance, it is essential to know the basics of components in Vue 3.

## Component Basics in Vue 3

Components are reusable pieces of UI code that can be used to build functional web applications. They can be used as building blocks for complex applications from scratch or as reusable pieces to prevent repeatedly rewriting similar codes.

In Vue, there is mainly a root component and then other components. These components act as objects that hold the state variables and component logic.

### Defining and Using a Component

There are different ways to define a component in Vue, but the most reliable method is using the Single-file Components, also known as SFCs. This popular feature of Vue.js allows you to write markup while keeping your component well-defined in one file. To create an SFC;

- Create a **`.vue`** file, e.g., **Checkbox.vue**.
- Define your template in a `template` tag and define the component in a `script` tag (this file then gets imported into your main Vue app).
```html
<template>
  <div class="checkbox-wrapper" @click="check">
    <div :class="{ checkbox: true, checked: checked }"></div>
    <div class="title">{{ title }}</div>
  </div>
</template>
<script>
```
To use a child component, we import it in the parent component using the following steps:

- Import the .vue file into the component script tag
- Add the default export to the component property

See here for more details on [Components Basics](https://vuejs.org/guide/essentials/component-basics.html).


## Nested Component and Listener Inheritance

Nested components involve using a component inside another component, allowing us to compress functionality and reuse them in multiple places in our Vue applications.

- For instance, given a `<MyButton>` component with the following template:
```html
<button>click me</button>
```
      
- And a parent with this component as:
```html
<MyButton class="large" />
```
- The final rendered DOM would be:
```html
<button class="large">click me</button>
```
- In the above code, the `<MyButton>` class is treated as a fallthrough attribute (an attribute that is passed to a component but is not declared in the receiving component's props) and automatically added to `<MyButton>`'s root element.
 
- Hence, to nest components, we refactor `<MyButton>` to render a `<BaseButton>` as its root instead:
```html
<BaseButton />
```      
- Then the fallthrough attributes received by `<MyButton>` will be automatically forwarded to `<BaseButton>`.

On the part of `v-on` listener Inheritance, they are attributes used to pass an event to be invoked in the child component. Considering our previous code example:

```javascript
<MyButton @click="onClick" />
```
The click listener will be added to the root element of `<MyButton>`, i.e., the initial `<button>` element with this code:
```html
<button>click me</button>
```
When the native `<button>` is clicked, it automatically triggers the onClick method of the parent component. If the native `<button>` already has a click listener bound with `v-on`, both listeners will be triggered.



<div style="background-color:#efefef; border-radius:8px; padding:10px; display:block;">
<hr/>
<h3><em>Session Replay for Developers</em></h3> 
<p><em>Uncover frustrations, understand bugs and fix slowdowns like never before with <strong><a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a></strong> — an open-source session replay suite for developers. It can be <strong>self-hosted</strong> in minutes, giving you complete control over your customer data.</em></p>
<img alt="OpenReplay" style="margin-top:5px; margin-bottom:5px;" width="768" height="400" src="https://raw.githubusercontent.com/openreplay/openreplay/main/static/openreplay-git-hero.svg" class="astro-UXNKDZ4E" loading="lazy" decoding="async">
<p><em>Happy debugging! <a href="https://openreplay.com" target="_blank">Try using OpenReplay today.</a></em><p>
<hr/>
</div>





## Passing Props as Attributes in Vue 3

When passing props as attributes in Vue 3, we consider the various prop types, and they include;

- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol

However, if the type of the data passed does not match the prop type, Vue sends a warning alert (in development mode) to the console. So, you must ensure that any data passed matches a particular prop type. The main goal of using props is to pass down data; this can either be passed as a data property using v-bind, such as in this code:
```html
<template>
  <ComponentName :title=title />
</template>
 
<script>
export default {
  //...
  data() {
    return {
      title: 'How to Use Attribute Inheritance in Vue 3'
    }
  },
  //...
}
</script>
```
Or it can be passed as a static value:
```html
<ComponentName title="How to Use Attribute Inheritance in Vue 3" />
```
Let’s see how to use both methods in a simple code example. Assuming we are building an app that has many buttons with different text/background colors. Instead of repeating the button syntax in all our files, we create a button component and pass these text/background colors as props.
 
The parent component:
```html
<template>
  <div id="app">
    <Button :name='btnName' bgColor='red' />
    <Button :name='btnName' bgColor='green' />
    <Button :name='btnName' bgColor='blue' />
  </div>
</template>
 
<script>
import Button from './components/Button'
 
export default {
  name: 'App',
  data(){
    return{
      btnName:"Chris",
    }
  },
  components: {
    Button
  }
}
    </script>
```
 
The child component:
```html
<template>
  <button class="btn" :style="{backgroundColor:bgColor}">{{name}}</button>
</template>
<script>
export default {
  name: 'Button',
  props:{
    name:String,
    bgColor:String
  }
}
</script>
```
The above code depicts how to use data property and static values when data comes from a parent component and is also used in a child component.


## Non-Prop Attributes and Multiple Root Nodes

For components with multiple root nodes, they do not have an automatic attribute fallthrough behavior (this means that they are not like single root node components that automatically inherit from the parent because Vue cannot be sure where to apply the fallthrough attributes). If `$attrs` are not bound explicitly, a warning will be issued.
**For example:**
```javascript
<custom-layout id="custom-layout" @click="changeValue"></custom-layout>
// This will raise a warning
app.component('custom-layout', {
  template: `
    <header>...</header>
    <main>...</main>
    <footer>...</footer>
  `
})
 
// No warnings, $attrs are passed to <main> element
app.component('custom-layout', {
  template: `
    <header>...</header>
    <main v-bind="$attrs">...</main>
    <footer>...</footer>
  `
})
```
## Replacing/Merging Attribute Values

Attributes can be replaced or merged from elements in the parent components. For example, let’s take style and class attributes; for instance, if the child component's root element already has existing class or style attributes, it will be merged with the class and style values inherited from the parent.

Let’s change the template of `<MyButton>` in our previous example to:
```html
<button class="btn">click me</button>
```
Then the final rendered DOM would now become:
```html
<button class="btn large">click me</button>
```
## Disabling Attribute Inheritance

If you do not want a component to inherit attributes automatically, you can set `inheritAttrs`: false in the component's options.
 
In cases where attributes need to be applied to other elements besides the root node, attribute inheritance can be disabled. By setting the `inheritAttrs` option to false, you can now apply attributes to other element attributes; this enables the component’s `$attrs` property and allows you to take complete control over where the fallthrough attributes should be applied.

## Summary

In this tutorial, we examined how to use attribute inheritance in Vue 3 by enumerating its types, emphasizing the basics of components, and explaining nested components with `v-on` listeners. We also discussed how to effectively pass props, handle attributes on multiple root nodes, and merge/replace and disable attributes.
 
### Resources
- https://www.codimth.com/blog/web/vuejs/how-use-attribute-inheritance-vuejs
-  https://javascript.plainenglish.io/vue-3-prop-types-and-non-prop-attributes-inheritance-a4d1a5540108
-  https://vuejs.org/guide/components/attrs.html
- https://www.freecodecamp.org/news/how-to-use-props-in-vuejs/