Skip to content
Advertisement

How to use slots in the HTML with Single File Components

I want to use slots in Vue to create a dynamic modal component.

I already tried a lot of tutorials of Vue / slots, but none of them is exactly what i’m looking for.

This is a piece of my modal.vue:

<template>
  ...
    <slot name="modal-body"></slot>
  ...
</template>
<script>
</script>
<style>
</style>

This is my javascript compiled file:

import Vue from 'vue';
import modal from './modal.vue';

new Vue({
  el: '#modal',
  render: r => r(modal)
});

This is piece of my HTML file:

...
<div id="modal">
  <template v-slot="modal-body">
    <input type="text" id="dynamic-input">
  </template>
</div>
...

I was expecting that all elements present inside #modal (#dynamic-input in this case), were inserted into the slot named modal-body, inside my Vue element. Is it possible to do it? Am i missing something?

Advertisement

Answer

Check what version of Vue you are using. The named slot syntax changed in 2.6.0. Consider the differences below. One uses render functions and the other template Strings.

Vue@2.6.10

// Example using template String
const modalTemplateString = {
  template: "<div><div>above</div><slot name="modal-body"></slot><div>below</div></div>"
};

const appTemplateString = new Vue({
  el: "#appTemplateString",
  components: {
    modal: modalTemplateString
  },
  template: "<div><modal><template v-slot:modal-body><div>foobar</div></template></modal></div>"
});

// Example using render function
const modalRenderFunc = {
  render(h) {
    return h("div", [
      h("div", "above"),
      h("div", this.$slots["modal-body"]),
      h("div", "below")
    ]);
  }
}

const appRenderFunc = new Vue({
  el: "#appRenderFunc",
  components: {
    modal: modalRenderFunc
  },
  render(h) {
    return h("div", [
      h("modal", [
        h("div", {
          slot: "modal-body"
        }, "foobar")
      ])
    ]);
  }
});
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>

<h2>Template String</h2>
<div id="appTemplateString"></div>
<hr/>
<h2>Render Function</h2>
<div id="appRenderFunc"></div>

Vue@2.5.22

// Example using template String
const modalTemplateString = {
  template: "<div><div>above</div><slot name="modal-body"></slot><div>below</div></div>"
};

const appTemplateString = new Vue({
  el: "#appTemplateString",
  components: {
    modal: modalTemplateString
  },
  template: "<div><modal><template slot="modal-body"><div>foobar</div></template></modal></div>"
});

// Example using render function
const modalRenderFunc = {
  render(h) {
    return h("div", [
      h("div", "above"),
      h("div", this.$slots["modal-body"]),
      h("div", "below")
    ]);
  }
}

const appRenderFunc = new Vue({
  el: "#appRenderFunc",
  components: {
    modal: modalRenderFunc
  },
  render(h) {
    return h("div", [
      h("modal", [
        h("div", {
          slot: "modal-body"
        }, "foobar")
      ])
    ]);
  }
});
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script>

<h2>Template String</h2>
<div id="appTemplateString"></div>
<hr/>
<h2>Render Function</h2>
<div id="appRenderFunc"></div>
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement