"Non-function value encountered for default slot." in Vue 3 Composition API component

To resolve the error "Non-function value encountered for default slot." in a Vue 3 Composition API component, you can follow these steps:

  1. Check your component's template for any default slots that are expecting a function but receiving a non-function value instead. Default slots in Vue expect functions as their values.
  2. Inspect the component's usage to ensure that you are passing a function to the default slot. If you're passing a variable or a non-function value, it could lead to this error.
  3. If you're using a template syntax like <template>, ensure that the default slot's value is indeed a function. For example:
<template>
  <MyComponent>
    {{ slotValue }}
  </MyComponent>
</template>

<script>
import { defineComponent } from 'vue';

export default defineComponent({
  setup() {
    const slotValue = () => {
      // Your slot logic here
    };

    return { slotValue };
  },
});
</script>

Make sure that slotValue is indeed a function in the setup function.

The following might not help the original poster of the question as they seem to have already solved their issue. However, I wanted to share that I encountered the same warning message because I was using a component and instead of having its closing tag just at its end - i.e. <v-select ...misc props...></v-select>, I decided to align the closing tag with the opening one, i.e.:


<v-select  ...misc props...
           ...and event handlers...  >
</v-select>
    

This creates a text node (and thus content for the default slot) between the > and the <.

Changing to either:


<v-select  ...misc props...
           ...and event handlers...  ></v-select>
    

or


<v-select  ...misc props...
           ...and event handlers...  
></v-select>
    

solves the issue, and the warning is not displayed anymore.

The correct solution to hide this warning is to change array children to:


{
  default: () => children,
}
    

For your example, it must be changed to this:


return () =>
  h(HelloWorld, {}, {
    default: () => [h("div", {}, ["Div 1"]), h("div", {}, ["Div 2"])],
  });
    

Instead of rendering the child slot directly in the parent component (i.e., passing an array of VNodes as the slots argument directly), wrap it in a function:


// src/components/Composite.js
export default defineComponent({
  setup(props, { slots }) {
    return () =>          👇
      h(HelloWorld, {}, () => [h("div", {}, ["Div 1"]), h("div", {}, ["Div 2"])]);
  }
});
    

Note that the inner h() calls don't need this function wrapper because they're all rendered together with the default slot by the child component.