vue-v-slot-example-feature-image

Vue v-slot tutorial with examples

Vue 2.6 is released with new syntax for Slots using v-slot directive. In this tutorial, we’re gonna show you:

  • Syntax to use Vue Slot with v-slot directive along with its shorthand
  • How to use Vue Named Slots with v-slot & examples
  • How to use Vue v-slot for Scoped Slots & examples
  • Vue Dynamic slots example

Related Post: Vue 3 Composition API tutorial with examples


Vue slots syntax with v-slot directive

With new v-slot directive, we can:
– combine html layers: component tag and scope of the slot.
– combine the slot and the scoped slot in a single directive.

For example, this is old syntax with slot-scope:

<ListComponent>
  <template slot-scope="{items}">
    <p v-for="item in items :key="item">{{item}}</p>
  </template>
</ListComponent>

This is how we combine ListComponent and template tag:

<ListComponent v-slot="{items}">
  <p v-for="item in items" :key="item">{{item}}</p>
</ListComponent>

And this is old named slots syntax:

<base-component>
  <p slot="header">Header</p>

  <template slot="content" slot-scope="{data}">
    <h2>{{data.title}}</h2>
    <p>{{data.text}}</p>
  </template>

  <p slot="footer">Footer</p>
</base-component>

Now we use new Vue v-slot directive:

<base-component>
  <template v-slot:header>
    <p>Header</p>
  </template>

  <template v-slot:content="{data}">
    <h2>{{data.title}}</h2>
    <p>{{data.text}}</p>
  </template>

  <template v-slot:footer>
    <p>Footer</p>
  </template>
</base-component>

You can see that:

– We use <template v-slot:header> to wrap <p> tag instead of <p slot="header"> directly. This is because Vue v-slot can only be used in <component> or <template> html tag. It cannot be used in plain HTML tags (<p> for example).

– We replace slot="content" slot-scope="{data}" with v-slot:content="{data}" by combining slot & slot-scope. With new Vue v-slot directive, all slots are compiled into scoped slots. It improves the performance. Why?

Normal slots are rendered during the parent component’s render cycle. So, if any dependency of a slot changes, both the parent and child components will be re-rendered.

When we use scoped slots, slots are compiled into inline functions and called during the child component’s render cycle. This means:

  • data from a scoped slot are collected by the child component which is re-rendered separately.
  • the changes of parent scope dependency only affect the parent, not the child component. So the child component doesn’t need to update if it uses only scoped slots.

Shorthand for v-slot

# is the shorthand for Vue v-slot directive.
For example, #content stands for v-slot:content.

The code above can be written as:

<base-component>
  <template #header>
    <p>Header</p>
  </template>

  <template #content="{data}">
    <h2>{{data.title}}</h2>
    <p>{{data.text}}</p>
  </template>

  <template #footer>
    <p>Footer</p>
  </template>
</base-component>

Remember that when using shorthand, we must always specify the name of the slot after # symbol. We cannot use shorthand like this: #="{item}".
It must be: #default="{item}" in which, #default is the shorthand for v-slot:default.

In the next parts, we show you some examples that apply new Vue v-slot directive in practice.

Vue v-slot examples with Named Slots

If we want to use multiple slots in one component, Named Slots are useful.
The code below shows BkrCard component template with 3 slots:

  • header
  • title
  • default
<template>
  <div class="card">
    <div class="card-img-top">
      <slot name="header"></slot>
    </div>
    <div class="card-body">
      <div class="card-title">
        <slot name="title">Default Card title</slot>
      </div>
      <div class="card-text">
        <slot>This is just a default Card text</slot>
      </div>
    </div>
  </div>
</template>

Remember that <slot> without name attribute has the name default.

Now look at the parent component which use v-slot directive to specify name for named slots on <template> tag:

<bkr-card>
  <template v-slot:header>
    <img src="https://bezkoder.com/wp-content/uploads/2019/06/bezkoder-test-feature-image.png">
  </template>

  <template v-slot:title>
    <p>BezKoder for mobile developers</p>
  </template>

  <template v-slot:default>
    <p>BezKoder.com is built for specific goal: programming languages & technique for mobile application, cross-platform software development.</p>
    <bkr-button>Read more</bkr-button>
  </template>
</bkr-card>

The result will be:

vuejs-v-slot-examples-named-slots-result

If we pass only one named slot, the default value will be shown:

<bkr-card>
  <template v-slot:header>
    <img src="https://bezkoder.com/wp-content/uploads/2019/06/bezkoder-test-feature-image.png">
  </template>
</bkr-card>

vuejs-v-slot-examples-named-slots-default-value-result

Vue v-slot example with default slot

In the example above, we use <template v-slot:default> for the default slot.

We have other ways to specify html code to be considered as default slot also:

– wrap it in a <template> without Vue v-slot directive:

<bkr-card>
  <template v-slot:header>
    <img src="https://bezkoder.com/wp-content/uploads/2019/06/bezkoder-test-feature-image.png">
  </template>

  <template v-slot:title>
    <p>BezKoder for mobile developers</p>
  </template>

  <template>
    <p>BezKoder.com is built for specific goal: programming languages & technique for mobile application, cross-platform software development.</p>
    <bkr-button>Read more</bkr-button>
  </template>
</bkr-card>

– do not wrap it in a <template>:

<bkr-card>
  <template v-slot:title>
    <p>BezKoder for developers</p>
  </template>

  <p>BezKoder.com is built for specific goal: programming languages & technique for mobile application, cross-platform software development.</p>
  <bkr-button>Read more</bkr-button>

  <template v-slot:header>
    <img src="https://bezkoder.com/wp-content/uploads/2019/06/bezkoder-test-feature-image.png">
  </template>
</bkr-card>

The result are the same for 2 cases:

vuejs-v-slot-examples-named-slots-result

Vue v-slot examples with Scoped Slots

What we should do when we want a child component to allow parent component access its data?

In this example, categories need to be available to the slot content in the parent. So we bind the categories as an attribute to the <slot> element:

<template>
  <span>
    <slot :categories="categories"></slot>
  </span>
</template>

<script>
export default {
  data() {
    return {
      categories: ["Dart", "Flutter", "Vue.js"],
    };
  }
};
</script>

The categories attribute is called slot props.
In the parent scope, Vue v-slot directive can help us get value of the slot props above:

<bkr-categories v-slot="{categories}">
  <ul>
    <li v-for="category in categories" :key="category">
      {{ category }}
    </li>
  </ul>
</bkr-categories>

The result will be:

  • Dart
  • Flutter
  • Vue.js

This is shorthand for v-slot:

<bkr-categories #default="{categories}">
  <ul>
    <li v-for="category in categories" :key="category">
      {{ category }}
    </li>
  </ul>
</bkr-categories>

Vue Dynamic slots example

We can use a JavaScript expression in v-slot directive argument with square brackets:

<base-component>
  <template v-slot:[collection]="{data}">
    {{data.item}}
  </template>
</base-component>

Now look at the example:

<bkr-categories v-slot:[collection]="{categories}">
  <ul>
    <li v-for="category in categories" :key="category">
      {{ category }}
    </li>
  </ul>
</bkr-categories>
<button class="btn btn-outline-secondary" @click="changeCollection">Change</button>

<script>
import BkrCategories from "./components/BkrCategories.vue";

export default {
  components: {
    BkrCategories
  },
  data() {
    return {
      collection: "default"
    };
  },
  methods: {
    changeCollection() {
      if (this.collection === "default") this.collection = "new_categories";
      else this.collection = "default";
    }
  }
};
</script>

Clicking on the Change button will change the collection value dynamically.
v-slot:[collection]="{categories}" could become:

  • v-slot:default="{categories}"
  • v-slot:new_categories="{categories}"

This is BkrCategories component with default and new_categories slot name:

<template>
  <span>
    <slot :categories="categories"></slot>
    <slot name="new_categories" :categories="newCategories"></slot>
  </span>
</template>

<script>
export default {
  data() {
    return {
      categories: ["Dart", "Flutter", "Vue.js"],
      newCategories: ["Mobile", "Cross Platform", "Frontend Tech"],
    };
  }
};
</script>

The result will be:

vuejs-v-slot-examples-dynamic-named-slots

Conclusion

We’ve learned almost aspects of new Vue v-slot directive, from v-slot syntax to its handshort, then apply v-slot directive on Named Slot examples to Scoped Slots and Dynamic Slots examples.

Happy learning! See you again!

Further reading

One thought to “Vue v-slot tutorial with examples”

Leave a Reply

Your email address will not be published. Required fields are marked *