Subscribe on changes!

Extraneous non-props attributes (class) were passed to component but could not be automatically inherited because component renders fragment or text root nodes.

avatar
May 17th 2022

Link to minimal reproduction

https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cCBsYW5nPVwidHNcIj5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcbmltcG9ydCBNZW51SXRlbSBmcm9tICcuL01lbnVJdGVtLnZ1ZSdcblxuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cbiAgPE1lbnVJdGVtIHRvPScvdXNlci9zZXR0aW5ncycgY2xhc3M9XCJtZW51LWl0ZW1cIj5cbiAgICBQcm9maWxlXG4gIDwvTWVudUl0ZW0+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0iLCJNZW51SXRlbS52dWUiOiI8dGVtcGxhdGU+XG4gIDx0ZW1wbGF0ZSB2LWlmPVwidG9cIj5cbiAgICA8Um91dGVyTGluayB2LWlmPVwiaXNSb3V0ZVwiIDp0bz1cImhyZWZcIiB2LWJpbmQ9XCJjb21tb25BdHRyc1wiIDpjbGFzcz1cImNsYXNzTGlzdFwiPlxuICAgICAgPHNsb3QgLz5cbiAgICA8L1JvdXRlckxpbms+XG4gICAgPGEgdi1lbHNlIDpocmVmPVwiaHJlZlwiIHYtYmluZD1cImNvbW1vbkF0dHJzXCIgOmNsYXNzPVwiY2xhc3NMaXN0XCI+XG4gICAgICA8c2xvdCAvPlxuICAgIDwvYT5cbiAgPC90ZW1wbGF0ZT5cbiAgPGRpdiB2LWVsc2Ugdi1iaW5kPVwiY29tbW9uQXR0cnNcIiA6Y2xhc3M9XCJjbGFzc0xpc3RcIj5cbiAgICA8c2xvdCAvPlxuICA8L2Rpdj5cbjwvdGVtcGxhdGU+XG48c2NyaXB0IGxhbmc9XCJ0c1wiIHNldHVwPlxuaW1wb3J0IHsgY29tcHV0ZWQsIGluamVjdCwgdXNlQXR0cnMgfSBmcm9tICd2dWUnXG5pbXBvcnQgdHlwZSB7IFJvdXRlTG9jYXRpb25SYXcgfSBmcm9tICd2dWUtcm91dGVyJ1xuaW1wb3J0IHVzZUxpbmsgZnJvbSAnLi91c2VMaW5rLnRzJ1xuXG5pbnRlcmZhY2UgUHJvcHMge1xuICB0bz86IFJvdXRlTG9jYXRpb25SYXdcbn1cblxuY29uc3QgcHJvcHMgPSBkZWZpbmVQcm9wczxQcm9wcz4oKVxuY29uc3QgZW1pdCA9IGRlZmluZUVtaXRzKFsnY2xpY2snXSlcblxuY29uc3QgYXR0cnMgPSB1c2VBdHRycygpXG5jb25zdCB7IGhyZWYsIGlzUm91dGUgfSA9IHVzZUxpbmsocHJvcHMsIGF0dHJzKVxuXG5jb25zb2xlLmxvZyhocmVmLCBpc1JvdXRlKVxuXG5jb25zdCBjbGFzc0xpc3QgPSBjb21wdXRlZCgoKSA9PiB7XG4gIHJldHVybiBbJ2UtbWVudS1pdGVtJ11cbn0pXG5cbmNvbnN0IG9uQ2xpY2sgPSAoKSA9PiB7XG4gIGNvbnNvbGUubG9nKCdjbGljaycpXG59XG5cbmNvbnN0IG9uTW91c2VvdmVyID0gKCkgPT4ge1xuICBjb25zb2xlLmxvZygnbW91c2VvdmVyJylcbn1cblxuY29uc3QgY29tbW9uQXR0cnMgPSB7XG4gIC4uLmF0dHJzLFxuICBvbkNsaWNrLFxuICBvbk1vdXNlb3Zlcixcbn1cbjwvc2NyaXB0PlxuIiwidXNlTGluay50cyI6ImltcG9ydCB7IHJlc29sdmVEeW5hbWljQ29tcG9uZW50IH0gZnJvbSAndnVlJ1xuaW1wb3J0IHR5cGUgeyBTZXR1cENvbnRleHQgfSBmcm9tICd2dWUnXG5pbXBvcnQgdHlwZSB7XG4gIFJvdXRlckxpbmsgYXMgX1JvdXRlckxpbmssXG4gIFJvdXRlTG9jYXRpb25SYXcsXG59IGZyb20gJ3Z1ZS1yb3V0ZXInXG5cbmV4cG9ydCBpbnRlcmZhY2UgTGlua1Byb3BzIHtcbiAgaHJlZj86IHN0cmluZ1xuICByZXBsYWNlPzogYm9vbGVhblxuICB0bz86IFJvdXRlTG9jYXRpb25SYXdcbn1cblxuZXhwb3J0IGludGVyZmFjZSBVc2VMaW5rIHtcbiAgaXNSb3V0ZTogYm9vbGVhblxuICBocmVmOiBzdHJpbmdcbn1cblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdXNlTGluayAocHJvcHM6IExpbmtQcm9wcywgYXR0cnM6IFNldHVwQ29udGV4dFsnYXR0cnMnXSk6IFVzZUxpbmsge1xuICBpZiAoIXByb3BzLnRvKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlzUm91dGU6IGZhbHNlLFxuICAgICAgaHJlZjogbnVsbCxcbiAgICB9XG4gIH1cblxuICBjb25zdCBSb3V0ZXJMaW5rID0gcmVzb2x2ZUR5bmFtaWNDb21wb25lbnQoJ1JvdXRlckxpbmsnKSBhcyB0eXBlb2YgX1JvdXRlckxpbmsgfCBzdHJpbmdcblxuICBpZiAodHlwZW9mIFJvdXRlckxpbmsgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlzUm91dGU6IGZhbHNlLFxuICAgICAgaHJlZjogcHJvcHMudG8gYXMgc3RyaW5nLFxuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGxpbmsgPSBSb3V0ZXJMaW5rLnVzZUxpbmsocHJvcHMgYXMgUmVxdWlyZWQ8TGlua1Byb3BzPilcblxuICByZXR1cm4ge1xuICAgIC4uLmxpbmssXG4gICAgaXNSb3V0ZTogdHJ1ZSxcbiAgICBocmVmOiBsaW5rPy5yb3V0ZS52YWx1ZS5ocmVmLFxuICB9XG59XG4ifQ==

Steps to reproduce

Create a component with conditional rendering, each condition already has a single root.

<template>
  <template v-if="to">
    <RouterLink v-if="isRoute" :to="href" v-bind="commonAttrs" :class="classList">
      <slot />
    </RouterLink>
    <a v-else :href="href" v-bind="commonAttrs" :class="classList">
      <slot />
    </a>
  </template>
  <div v-else v-bind="commonAttrs" :class="classList">
    <slot />
  </div>
</template>
<script lang="ts" setup>
import { computed, inject, useAttrs } from 'vue'
import type { RouteLocationRaw } from 'vue-router'
import useLink from './useLink.ts'

interface Props {
  to?: RouteLocationRaw
}

const props = defineProps<Props>()
const emit = defineEmits(['click'])

const attrs = useAttrs()
const { href, isRoute } = useLink(props, attrs)

const classList = computed(() => {
  return ['e-menu-item']
})

const onClick = () => {
  console.log('click')
}

const onMouseover = () => {
  console.log('mouseover')
}

const commonAttrs = {
  ...attrs,
  onClick,
  onMouseover,
}
</script>

when I use this component and pass a class attribute it outputs the following warning.

<MenuItem class="menu-item" to="/user/settings">
  Profile
</MenuItem>

[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.

image

What is expected?

Should not show this warning as the component is rendering with a single root.

What is actually happening?

This is the rendered HTML with the warning [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.

<a href="/user/settings" class="menu-item e-menu-item"><!--[--> Profile <!--]--></a>

System Info

System:
    OS: macOS 10.15.7
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 934.50 MB / 16.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 16.8.0 - /usr/local/bin/node
    Yarn: 1.22.17 - ~/.yarn/bin/yarn
    npm: 7.21.0 - /usr/local/bin/npm
  Browsers:
    Chrome: 101.0.4951.64
    Edge: 101.0.1210.47
    Firefox: 100.0
    Safari: 15.4


### Any additional comments?

_No response_
avatar
May 19th 2022

maybe you can add div element for the root node.

avatar
May 19th 2022

@ChpShy aware of this way, just want to avoid some unnecessary DOM nodes.

avatar
Jun 23rd 2022

It's a bit of a question how deep the compiler should follow this rabbit hole of nested v-if fragments, but it should be doable. We'll rarely have this more than 3 levels deep.

avatar
Feb 20th 2024

Is there any progress?