Subscribe on changes!

data-v- attribute sometimes missing for component rendered from defaulted prop

avatar
Aug 8th 2022

Vue version

3.2.33

Link to minimal reproduction

https://stackblitz.com/edit/heroicon-missing-data-v?file=src/App.vue

Steps to reproduce

Bug is already present in minimal reproduction.

What is expected?

When using to render a component passed in as a prop to the current component, the rendered component should always contain the current components data-v- attribute to allow scoped styling to take place.

What is actually happening?

If no component is passed in as a prop, and we default the prop with a Heroicon component using withDefaults(), then the rendered component is missing the data-v- attribute and does not receive scoped styling. When passing in a Heroicon component as a prop, the data-v- attribute renders as normal and scoped styling occurs.

System Info

System:
    OS: macOS 12.5
    CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
    Memory: 2.73 GB / 32.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.16.0 - ~/.nvm/versions/node/v16.16.0/bin/node
    npm: 8.13.2 - ~/.nvm/versions/node/v16.16.0/bin/npm
  Browsers:
    Chrome: 103.0.5060.134
    Safari: 15.6
  npmPackages:
    vue: 3.2.33 => 3.2.33

Any additional comments?

When trying to replicate just using components in the current NPM package, the data-v- attribute would render correctly even if the prop was defaulted. Was only able to replicate after using components imported from the "@heroicons/vue" package. I have not tested to see if it also occurs with all components imported from external packages.

avatar
Sep 17th 2022

Hi!

so the immediate fix is simple:

const props = withDefaults(defineProps<Props>(), {
  message:
    "This icon was defaulted inside of the component, and is missing the required 'data-v-' attribute for scoped styling",
-   icon: ChatIcon, 
+   icon: () => ChatIcon,
});
  1. These icons are functional components, meaning: plain functions
  2. in default props values, functions are used as factories and being run to generate a default value for each instance.
  3. So your code is actually generating a vnode outside of the component's render cycle.
  4. that vnode does not have the data-v property.
  5. and <component :is> does not re-apply this property is you pass it a static vnode instead of a component.

Now it's the last point that I'm not sure is intended, need some input from other maintainers.