Subscribe on changes!

API for slotted element/s to inherit attributes from a parent component

avatar
Mar 16th 2022

What problem does this feature solve?

I would like the ability to be able to wrap an element/s in a component that applies attributes to them. This can be useful as a way to apply extra features to an element/s without having to use unnecessary wrapper divs, or refs. Essentially, while there are often more verbose alternatives, I think the ability to make higher-order-components in Vue allows for useful patterns especially when used in component libraries.

What does the proposed API look like?

I'd like to make slots function similarly to components in that if they render a single child the child will get the passed $attrs, but if they render multiple children you have to v-bind them yourself.

An idea could be to have a v-attrs directive specifically for slots:

// MenuItem.vue (HOC to manage menu item attributes for any element simplified to just adding a role)
<template>
  <slot v-attrs="{ role: 'menuitem' }"></slot>
</template>

When used:

<template>
  <MenuItem><button /></MenuItem>
</template>

Would render:

<button role="menuitem" />

However if there are multiple elements/components in the slot you would get access to a $attrs prop on the slot scope that you could use to pass them to the children or a specific child of the slot:

<MenuItem>
  <template #default="{ $attrs: slotAttrs }">
    <button v-bind="slotAttrs" />
    <button v-bind="slotAttrs" />
  </template>
</MenuItem>

Addition idea to make slots more predictable:

Additionally, as a bonus to make component libraries more predicable and developer friendly it could be really cool to have a slot syntax for slots that expect only one element:

<slot-single />

Or maybe

<slot v-children="1" />

and possibly

<slot v-children="{ min: 2, , max: 10 }" />

where the v-children can be used on any element and throw an error if the child count doesn't match the provided range.

Let me know what you think!

avatar
Mar 16th 2022

This can and is already done with a v-bind by libraries like vuetify the way you showed. If you think this new syntax is worth pursuing, you should open an RFC in the rfcs repo