Subscribe on changes!

v-slot not working on component if mixing default and named slots - compiler error not helpful

avatar
Aug 26th 2022

Vue version

3.2

Link to minimal reproduction

https://stackblitz.com/edit/vue-ygckrr?file=src/App.vue

Steps to reproduce

  • Create a component with default slot, and named slots
  • On the Parent, use this component attaching v-slot on the component itself, and attach the method on a button.
  • The template won't compile

TabSelector

<template>
  <div>
    <slot :set-tab="setTab" />
  </div>
  <slot :name="modelvalue" />
</template>

App.vue

<script lang="ts" setup>
import { ref } from 'vue';
import TabSelector from './TabSelector.vue';
  
const currentTab = ref<'a' | 'b' | 'c'>('a');
</script>

<template>
  <TabSelector v-model="currentTab" v-slot="{ setTab }">
    <button @click="setTab('a')">
      Click on A
    </button>
    <button @click="setTab('b')">
      Click on B
    </button>
    <button @click="setTab('c')">
      Click on B
    </button>
    <template #a>
      This is A content
    </template>
    <template #b>
      This is A content
    </template>
    <template #c>
      This is A content
    </template>
  </TabSelector>
</template>

What is expected?

I shouldn't have to add an additional template tag to be able to use the scoped slot methods like this:

<template>
  <TabSelector v-model="currentTab">
    <template #default="{ setTab }"
      <div>
        <button @click="setTab('a')">Click on A</button>
        <button @click="setTab('b')">Click on B</button>
        <button @click="setTab('c')">Click on B</button>
      </div>
    </template>
    <template #a>A</template>
    <template #b>B</template>
    <template #c>C</template>
  </TabSelector>
</template>

What is actually happening?

It won't compile, and the message error is not clear. Codegen node is missing for element/if/for node. Apply appropriate transforms first. on StackBlitz, and Uncaught TypeError: can't access property "name", AppComponent is undefined on https://sfc.vuejs.org

System Info

No response

Any additional comments?

I have reasons to believe this is normal behaviour, however it is not documented and it took me time to guess it.

avatar
Aug 30th 2022

This is indeed expected behavior. Logically, if we allowed this template hierarchy, people would also expect to be able to use slot props from the default slot in the content of a named slot, because that's what the template would suggest:

<template>
  <TabSelector v-model="currentTab" v-slot="{ setTab }">
    <button @click="setTab('a')">
      Click on A
    </button>

    <template #a>
      This is A content
      <button @click="setTab('b')">
        Click on B
      </button>
      <button @click="setTab('c')">
        Click on B
      </button>
    </template>
    <template #b>
      This is A content
    </template>
    <template #c>
      This is A content
    </template>
  </TabSelector>
</template>

...but that does not work, as the named slots are not really nested in the default slot.

  • The compiler hints could be better though.
  • And this could be explained more clearly in the docs. Right now it's merely hinted at. I think the docs team would apprechiate if you could open a separate issue for this.