What Causes This Warning?
This warning occurs in render functions when you pass a non-function value where a slot function is expected. In Vue 3, slots should be functions that return VNodes.
The Problem
import { h } from 'vue'
// ❌ String instead of function
h(MyComponent, null, {
default: 'text content'
})
// ❌ VNode array instead of function
h(MyComponent, null, {
header: [h('h1', 'Title')]
})
The Fix
Use Functions for Slots
import { h } from 'vue'
// ✅ Function returning VNodes
h(MyComponent, null, {
default: () => 'text content',
header: () => h('h1', 'Title')
})
// ✅ Function returning array of VNodes
h(MyComponent, null, {
default: () => [
h('p', 'First paragraph'),
h('p', 'Second paragraph')
]
})
Common Scenarios
Basic Slot
// ❌ Wrong
h(Card, null, {
default: h('p', 'Content')
})
// ✅ Correct
h(Card, null, {
default: () => h('p', 'Content')
})
Named Slots
// ✅ Multiple named slots
h(Layout, null, {
header: () => h('h1', 'Page Title'),
default: () => h('main', 'Main content'),
footer: () => h('footer', 'Copyright 2024')
})
Scoped Slots
// ✅ Scoped slot with props
h(List, { items }, {
default: ({ item, index }) => h('li', `${index}: ${item.name}`)
})
Dynamic Slots
// ✅ Dynamic slot content
const slots = {
default: () => showContent.value
? h('div', 'Content')
: h('div', 'No content'),
header: () => h('h1', title.value)
}
h(Component, null, slots)
JSX Alternative
// ✅ JSX handles this automatically
<MyComponent>
{{
default: () => <p>Content</p>,
header: () => <h1>Title</h1>
}}
</MyComponent>
// Or children syntax for default slot
<MyComponent>
<p>This is default slot content</p>
</MyComponent>
Template vs Render Function
<!-- Template (simpler) -->
<template>
<MyComponent>
<template #header>
<h1>Title</h1>
</template>
<p>Default content</p>
</MyComponent>
</template>
<!-- Render function equivalent -->
<script>
export default {
render() {
return h(MyComponent, null, {
header: () => h('h1', 'Title'),
default: () => h('p', 'Default content')
})
}
}
</script>
Forwarding Slots
// ✅ Forward slots from parent
export default {
setup(props, { slots }) {
return () => h(ChildComponent, null, {
// Forward each slot as a function
default: slots.default,
header: slots.header ? () => slots.header() : undefined
})
}
}
Quick Checklist
- Slots in render functions must be functions
- Function should return VNode(s) or string
- Named slots:
{ slotName: () => content } - Scoped slots receive slot props as argument
- Use template syntax when possible for simpler code
- Forward slots using the slots object functions