Discover how to accomplish this task:
my-custom-component
code:
<template>
<third-party v-bind="$attrs">
<template v-slot:top="slotProps">
<slot name="top" v-bind="slotProps"></slot>
</template>
</third-party>
</template>
Explanation:
- Inserting the third party component and storing its attributes using
v-bind
$attrs
- Accessing the
top
slot of the third-party component
- The custom component contains a slot which is passed into the third-party's slot
- The custom slot has the same name so it can be accessed through
v-slot
from a parent component
- The custom slot binds all third-party
slotProps
to pass them out to a parent component
You can utilize a v-for
loop to make the process more dynamic, eliminating the need to hard-code an inner template for each slot. For instance, if you wish to expose two slots, top
and bottom
:
<template>
<third-party v-bind="$attrs">
<template v-for="slot in ['top','bottom']" v-slot:[slot]="slotProps">
<slot :name="slot" v-bind="slotProps"></slot>
</template>
</third-party>
</template>
Demonstration:
Vue.component('third-party', {
props: ['background'],
template: `
<div class="third" :style="{ background }">
3rd party slot:
<div class="third-slot">
<slot name="top" :props="props"></slot>
</div>
</div>
`,
data() {
return {
props: 'Third party Prop'
}
},
})
Vue.component('my-custom-component', {
template: `
<div>
<component is="third-party" v-bind="$attrs">
<template v-for="slot in ['top']" v-slot:[slot]="slotProps">
<slot :name="slot" v-bind="slotProps"></slot>
</template>
</component>
</div>
`
})
/***** APP *****/
new Vue({
el: "#app"
});
.third,.third-slot {
padding: 10px;
}
.third-slot {
background: #cccccc;
border: 1px solid #999999;
font-weight: bold;
}
<script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0a7c7f6f4a38243c243b38">[email protected]</a>/dist/vue.js"></script>
<div id="app">
<third-party background="#eeeeff">
<template v-slot:top="{ props: test }">
Some text on third-party component slot
<div>{{ test }}</div>
</template>
</third-party>
<my-custom-component background="red">
<template v-slot:top="{ props: test }">
Some text on third-party component slot
<div>{{ test }}</div>
</template>
</my-custom-component>
</div>
Fun Fact: You can even create the wrapped component dynamically like
<component :is="thirdpartyName">
and the array of slot names too; you could even pass this information from outside for a fully generic wrapper. However, that level of complexity is not required here.