Making reusable components using Vue Slot

Here are two reusable button components created using different types of slot methods.

The first one is a simple button. Just wrap the props from the parent component and pass them to the default slot called <slot></slot> in the child component.

// AppButton.vue
<template>
    <button>
        <slot>{{ text }}</slot>
    </button>
</template>

<script lang='ts' setup>
  const props = defineProps(['text']);
  const { text } = props
</script>
<!-- Parent.vue -->
<app-button>Cool button</app-button>

Secondly is named slot. We specify the name of multiple slots in child component, pass content from parent component based on the slot name set. In this example we set a fallback content of icon in slot named icon.

<!-- AppButton2 -->
<template>
    <button>
        <slot name="icon"> <akar-icons:heart class="inline-block" /> </slot>
        <slot name="default">{{ text }}</slot>
    </button>
</template>
<!-- Parent.vue -->
<app-button2>  second button </app-button2>

For each slot we wrap it in template following by v-slot:name or we can use shorthand #name. We may or not emit a default slot based on your preferences.

<!-- Parent.vue -->

<app-button2>
  <template v-slot:icon> 😊 </template>
  text passed to default slot
</app-button2>

<!-- shorthand -->
<app-button2>
  <template #icon>😊</template>
  <template #default>text passed to default slot</template>
</app-button2>

and they will look exactly the same like

Dynamic Scoped Slot

Sometimes we may want to switch slots dynamically based on reactive data. SelectedItem is an example of reactive data.

// Parent.vue
<template>
  <child>
   <template #[dynamicSlotName]="{ itemKey }">  // v-slot:[slotName]
      {{ itemKey }}  // item.fullname / item.firstname
   </template>
   <template #default></template>
  </child>
</templte>

<script setup>
const dynamicSlotName = ref('default')
</script>
// Child.vue
<template>
  <div v-for="item in items" :key="item.id">
    // bind dynamic value of item as props to be passed to parent
    <slot name="first" :itemKey="item.fullname"></slot> 
    <slot name="second" :itemKey="item.firstname"></slot> 
      // or  default slot
    <slot name="default" :itemKey="item"></slot> 
  </div>
</templte>

Happy learning!

Made with by leovoon