Reputation: 1620
I am trying to build a renderless component in vue 3 and want to pass a ref to the default slot.
When I am using the h
render function I can just pass a ref:
return h('div', {ref: someRef}); // works
If I try to do the same with the default slot, it does not work:
return slots.default({ ref: someRef}) // does not work
return slots.default({ someRef}) // also does not work
Is there any way to do this without wrapping the default slot into another div or similar?
Checked already the documentation and other resources, but couldn't find any solution.
Upvotes: 2
Views: 1291
Reputation: 92
Yes return a function from your setup
hook!
setup(_, slots) {
const someRef = ref()
return () => slots.default({ ref: someRef })
}
Yes, sometimes you just want a renderless (or headless as the kids these days say) wrapper for functionality (logic), without limiting the HTML that consumers can use.
But for that functionality to work, the renderless/headless component still needs to identify some of the HTML that consumers render into the default slot, in order to provide DOM-related functionality for example.
I have the same struggle when using this pattern, and have been relying on a "hack": passing specific data attributes via slot scope, that consumers need to bind to the desired elements (not only root) and then using good old document.querySelector
to grab them
I has served me well in vue2 and I've been using it in production with no problems, but I was wondering if with the new dynamic :ref
attribute of vue3, we can do it differently: probably passing a reactive ref
variable and then doing a simple assign, and apparently it works.
<renderless #default="{ someRef }">
<some-consumer-comp :ref="(el) => someRef.value = el" />
</renderless>
Do note that if you want to handle edge cases, like handling conditional rendering of slot content, you probably need to do a bit more work and add some watchers.
This pattern is a bit out of fashion these days, with the introduction of vue composables
since you can abstract the logic into a useSomeFunctionality
and use it directly on the component you want, but it's sill a valid one IMO.
Cheers!
Upvotes: 1