TL;DR: You can use arrow functions that return slot function calls to render scoped slots in the render function returned by setup
. Here's an SFC playground demonstrating the concept.
As of November 2021, the Vue 3 docs explain:
- How to return render functions from the
setup
function - How to set up scoped slots with a Vue template
- How to render scoped slots with a render function in the Options API
What's currently missing:
- How to render scoped slots in a render function inside the
setup
function
Took some tinkering to figure this out, but here's the trick:
// WithScopedSlot.ts
import { ref } from 'vue'
export const WithScopedSlot = {
setup (props, { slots }) {
const count = ref(0)
// Usually, we use `h(...)` to build and return VNodes. But the
// `slots` render functions also return VNodes, so if we're building
// a renderless component, we can omit `h(...)` entirely.
//
// Instead, we can just return an arrow function that returns a called slot:
return () => slots.default({
count: count.value,
onClick: () => count.value++,
})
}
}
This is handy, because it allows you to take full advantage of the Composition API via the setup
function, without sacrificing the flexibility of scoped slots and renderless components.
When you consume the component, you can use the scoped slot exactly as you normally would:
<!-- MyComponent.vue -->
<script>
import { WithScopedSlot } from './WithScopedSlot'
export default {
components: { WithScopedSlot }
}
</script>
<template>
<WithRenderFn v-slot="{ count, onClick }">
<div style="display: flex; gap: 1rem;">
<span>count is: {{ count }}</span>
<button :onClick="onClick">
Count up
</button>
</div>
</WithRenderFn>
</template>
How can we support multiple slots with renderless component ?