skip to Main Content

The full warning message:

[Vue warn]: Slot "default" invoked outside of the render function: this will not track dependencies used in the slot. Invoke the slot function inside the render function instead.

Nothing is broken and the functionality runs fine. I am just trying to clear this error.

Here is my code:

<template>
  <ul class="flex" data-test-id="tab-wrapper">
    <li
      v-for="(tab, index) in tabs"
      :key="index"
      @click="currentTab = tab"
    >
      {{ tab }}
    </li>
  </ul>
  <slot />
</template>


<script setup>
import { provide, ref, useSlots } from "vue";

const slots = useSlots();
const tabs = (slots.default && slots.default().map(tab => tab?.props?.title)) ?? [];
const currentTab = ref(tabs[0]);

provide("currentTab", currentTab);
</script>

It is my understanding that render() is implicit in the template, but I don’t know how to implement the way I am using slots in the template v-for.

Other questions that I have seen about this involve setup(props, context) or actually rendering the template using render() inside the script tag.

I’m brand new to Vue3/Composition API so I’m sure I did something wrong, but I’m having trouble figuring out exactly what. Any help is appreciated!

2

Answers


  1. I don’t have reputation to comment, but the solution is put the context on the <slot></slot>

    – The documentation

    – here an example

    Login or Signup to reply.
  2. UPDATE

    I’ve done it using render functions, just for sake of trying.

    I would not do it this way in real, since it’s too complicated and feels very like bad designed.

    const { createApp, ref, h, resolveComponent } = Vue;
    
    const Tab = {
      props: ['title'],
      template: 'Tab: {{ title }}'
    }
    
    const Tabpane = {
      components: { Tab },
      setup(props, { slots, expose }) {
        const currentTab = ref(null);
        const tab = resolveComponent('Tab')
        return () => h('div', null, 
          [
            h('div', null, 'Current Tab: ' + (currentTab.value ? currentTab.value.props?.title : '') ),
            h('ul', { class: 'flex', 'data-test-id' : 'tab-wrapper' }, 
             slots.default()?.map(tab => 
              h('li', 
                { onClick: () => { currentTab.value = tab } }, 
                tab.props.title)) ?? []          
            ),
            currentTab.value ? h(tab, 
              { title: currentTab.value?.props.title }, 
              currentTab 
            ) : null
         ])
      }
    }
    
    const App = { 
      components: { Tabpane }
    }
    const app = createApp(App)
    app.mount('#app')
    #app { line-height: 2; }
    [v-cloak] { display: none; }
    li { cursor: pointer; text-decoration: underline; color: blue;}
    <div id="app" v-cloak>
    <tabpane>
    <tab title="One"></tab>
    <tab title="Two"></tab>
    </tabpane>
    </div>
    <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
    <script type="text/x-template" id="tabpane">
      <ul class="flex" data-test-id="tab-wrapper">
        <li
          v-for="(tab, index) in tabs" :key="index" @click="currentTab = tab">
          {{ tab }}
        </li>
      </ul>
      <slot></slot>
    </script>

    This is a duplicate of the Vue 3 cli-service app: "Slot "default" invoked outside of the render function" warning when component with slots is imported from other component

    You should not use slots.default() outside the render() function.

    That’s what the Vue warning says.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search