Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vue 3 debugging reference for reactivity issues, computed errors, watcher bugs, async failures, and SSR hydration problems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
reference/rendering-render-function-slots-as-functions.md
1---2title: Pass Slots as Functions in Render Functions, Not Direct Children3impact: HIGH4impactDescription: Passing slot content incorrectly causes slots to not render or be treated as props5type: gotcha6tags: [vue3, render-function, slots, children, vnode]7---89# Pass Slots as Functions in Render Functions, Not Direct Children1011**Impact: HIGH** - When creating component vnodes with `h()`, children must be passed as slot functions, not as direct children. Passing children directly may cause them to be interpreted as props or fail to render.1213## Task Checklist1415- [ ] Pass slot content as functions: `{ default: () => [...] }`16- [ ] Use `null` for props when only passing slots to avoid misinterpretation17- [ ] For default slot only, a single function can be passed directly18- [ ] For named slots, use an object with slot function properties1920**Incorrect:**21```js22import { h } from 'vue'23import MyComponent from './MyComponent.vue'2425// WRONG: Children array may be misinterpreted26h(MyComponent, [27h('span', 'Slot content') // May not render as expected28])2930// WRONG: Named slots as direct properties31h(MyComponent, {32header: h('h1', 'Title'), // This is a prop, not a slot!33default: h('p', 'Content') // This is also a prop34})35```3637**Correct:**38```js39import { h } from 'vue'40import MyComponent from './MyComponent.vue'4142// CORRECT: Default slot as function43h(MyComponent, null, {44default: () => h('span', 'Slot content')45})4647// CORRECT: Single default slot shorthand48h(MyComponent, null, () => h('span', 'Slot content'))4950// CORRECT: Named slots as functions51h(MyComponent, null, {52header: () => h('h1', 'Title'),53default: () => h('p', 'Content'),54footer: () => [55h('span', 'Footer item 1'),56h('span', 'Footer item 2')57]58})5960// CORRECT: With props AND slots61h(MyComponent, { size: 'large' }, {62default: () => 'Button Text'63})64```6566## Why Functions?6768Slots in Vue 3 are functions for lazy evaluation:6970```js71// Slots are called by the child component when needed72// This enables:73// 1. Scoped slots (passing data back)74// 2. Conditional rendering (slot not called if not used)75// 3. Proper reactivity tracking7677h(MyList, { items }, {78// Scoped slot - receives data from child79item: ({ item, index }) => h('li', `${index}: ${item.name}`)80})81```8283## The null Props Gotcha8485When passing only slots, always use `null` for props:8687```js88// WRONG: Slots object interpreted as props!89h(MyComponent, {90default: () => 'Hello'91})92// MyComponent receives: props.default = () => 'Hello'9394// CORRECT: null signals "no props, next arg is slots"95h(MyComponent, null, {96default: () => 'Hello'97})98// MyComponent receives slot correctly99```100101## Forwarding Slots from Parent102103```js104export default {105setup(props, { slots }) {106return () => h(ChildComponent, null, {107// Forward all slots from parent108...slots,109110// Or forward specific slots111default: slots.default,112header: slots.header113})114}115}116```117118## Scoped Slots in Render Functions119120```js121// Parent: Receives data from child via slot props122h(DataTable, { data: items }, {123row: (slotProps) => h('tr', [124h('td', slotProps.item.name),125h('td', slotProps.item.value)126])127})128129// Child (DataTable): Calls slot with data130export default {131props: ['data'],132setup(props, { slots }) {133return () => h('table', [134h('tbody',135props.data.map(item =>136// Pass data to slot function137slots.row?.({ item })138)139)140])141}142}143```144145## Common Patterns146147```js148// Wrapper component forwarding slots149h('div', { class: 'wrapper' }, [150h(InnerComponent, null, slots)151])152153// Conditional slot rendering154h('div', [155slots.header?.(), // Optional chaining - only render if slot provided156h('main', slots.default?.()),157slots.footer?.()158])159160// Slot with fallback content161h('div', [162slots.default?.() ?? h('p', 'Default content when slot not provided')163])164```165166## Reference167- [Vue.js Render Functions - Passing Slots](https://vuejs.org/guide/extras/render-function.html#passing-slots)168- [Vue.js Render Functions - Children](https://vuejs.org/guide/extras/render-function.html#children)169