please, I'm learning a VueJS 3 and I have probably begineer problem. I have warn in browser developer console like this one:
The Message is:
[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.
I'm passing array of objects to the child Component. In my parent views/Home.vue compoment I have this implemenation:
<template>
<div class="wrapper">
<section v-for="(item, index) in items" :key="index" class="box">
<ItemProperties class="infobox-item-properties" :info="item.properties" />
</section>
</div>
</template>
<script>
import { ref } from 'vue'
import { data } from '@/data.js'
import ItemProperties from '@/components/ItemProperties.vue'
export default {
components: {
ItemDescription,
},
setup() {
const items = ref(data)
return {
items,
}
},
</script>
In child compoment components/ItemProperties.vue I have this code:
<template>
<div class="infobox-item-property" v-for="(object, index) in info" :key="index">
<span class="infobox-item-title">{{ object.name }}:</span>
<span v-if="object.type === 'rating'">
<span v-for="(v, k) in object.value" :key="k">{{ object.icon }}</span>
</span>
<span v-else>
<span>{{ object.value }}</span>
</span>
</div>
</template>
<script>
export default {
props: {
info: {
type: Array,
required: false,
default: () => [
{
name: '',
value: '',
type: 'string',
icon: '',
},
],
},
},
}
</script>
It doesn't matter if I have default() function or not. Also doesn't matter if I have v-if condition or not. If I have cycle in the Array, I got this warning
Data are in data.js file. The part of file is here:
export const data = [
{
title: 'White shirt',
properties: [
{ name: 'Material', value: 'Cotton', type: 'string', icon: '' },
{ name: 'Size', value: 'M', type: 'string', icon: '' },
{ name: 'Count', value: 4, type: 'number', icon: '' },
{ name: 'Absorption', value: 4, type: 'rating', icon: '💧' },
{ name: 'Rating', value: 2, type: 'rating', icon: '⭐️' },
{ name: 'Confort', value: 2, type: 'rating', icon: '🛏' },
{ name: 'Sleeves', value: 'Short', type: 'string', icon: '' },
{ name: 'Color', value: 'White', type: 'string', icon: '' },
],
},
]
PS: Application works but I'm afraid about that warning. What can I do please like right way?
I will be glad for any advice. Thank you very much.
The ItemProperties component has multiple root nodes because it renders a list in the root with v-for.
Based on the class name (infobox-item-properties), I think you want the class to be applied to a container element, so a simple solution is to just add that element (e.g., a div) in your component at the root:
// ItemProperties.vue
<template>
<div>
<section v-for="(item, index) in items" :key="index" class="box">
...
</section>
</div>
</template>
Well I think the error message is pretty clear.
Your ItemProperties.vue component is rendering fragments - because it is rendering multiple <div> elements using v-for. Which means there is no single root element.
At the same time, you are passing a class to the component with <ItemProperties class="infobox-item-properties" - class can be placed on HTML elements only. If you place it on Vue component, Vue tries to place it on the root element of the content the component is rendering. But because the content your component is rendering has no root element, Vue does not know where to put it...
To remove the warning either remove the class="infobox-item-properties" or wrap the content of ItemProperties to a single <div>.
The mechanism described above is called Fallthrough Attributes ("Non-prop attributes" Vue 2 docs). It is good to know that this automatic inheritance can be switched off which allows you to apply those attributes by yourself on the element (or component) you choose besides the root element. This can be very useful. Most notably when designing specialized wrappers around standard HTML elements (like input or button) or some library component...
You could also prevent passing down attributes in child components by doing this:
export default defineComponent({
name: "ChildComponentName",
inheritAttrs: false // This..
})