Home > Software engineering >  Vue3 pass component as prop
Vue3 pass component as prop

Time:03-17

i'm building a tab component where i need to pass component as a prop.

how can i display the component passed in the props?

Tab.vue

<template>
  <div >
    <button @click="activeTab = title" v-for="title in titles" v-text="title"
            
            :/>
  </div>
  <div >
    <component :is="activeTab"></component> // not working
  </div>
</template>
<script setup>
import {onMounted, ref} from "vue";

const props = defineProps({
  titles: {},
  tabs: {}
})
const activeTab = ref("")
onMounted(() => {
  activeTab.value = props.titles[0]
})
</script>

Settings.vue

<template>
  <Tab :titles="[$t('languagesLabel'),$t('countriesLabel')]" :tabs="[Languages,Countries]">
  </Tab>
</template>
<script setup>
import Tab from "../../components/admin/common/Tab.vue";
import Countries from "../../components/admin/settings/Countries.vue";
import Languages from "../../components/admin/settings/Languages.vue";
</script>

the question is how to make the displayed component dynamic ?

CodePudding user response:

You could use slot to pass components instead of props :

  <div >
    <slot/>
  </div>

in Settings.vue :


<template>
  <Tab :titles="[$t('languagesLabel'),$t('countriesLabel')]" >
    <Countries />
    <Languages />
  </Tab>
</template>
<script setup>
import Tab from "../../components/admin/common/Tab.vue";
import Countries from "../../components/admin/settings/Countries.vue";
import Languages from "../../components/admin/settings/Languages.vue";
</script>

CodePudding user response:

When using <script setup>, the <component>.is prop needs to be set to the component definition itself (not the component's name).

One solution is to track the active index (instead of active tab component):

  1. Change activeTab to be a computed prop that returns the current tab from tabs[] based on the active index.

  2. Create an activeIndex ref, initialized to 0.

  3. In the v-for, include the index iterator

  4. In the button's click handler, set the activeIndex to the current index.

  5. In the class binding, compare the current index to activeIndex.

<script setup>
import { onMounted, ref, computed } from 'vue'

const props = defineProps({
  titles: {},
  tabs: {},
})
         1️⃣
const activeTab = computed(() => props.tabs[activeIndex.value])
         2️⃣
const activeIndex = ref(0)
</script>
<template>
  <div >
    <button
                       3️⃣
      v-for="(title, index) in titles"
                  4️⃣
      @click="activeIndex = index"
      v-text="title"
      
                 5️⃣
      :
    />
  </div>
  <div >
    <component :is="activeTab"></component>
  </div>
</template>

Also, make sure to call markRaw() on the component definitions in the binding to avoid the unnecessary overhead of reactivity. This also resolves a Vue warning about this in the browser console.

<template>                                                         
  • Related