Categories
JavaScript Vue

Vue.js Components — Slots and Dynamic Components

Spread the love

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at distributing components with slots and dynamic components.

Distributing Components with Slots

We can pass content in components by putting text between the opening and closing tags.

To do this, we can add a slot to our component with the slot element.

For example, we can use it as follows:

src/index.js :

Vue.component("error-box", {  
  template: `  
    <div v-bind:style="{color: 'red'}">  
      <slot></slot>  
    </div>  
  `  
});

new Vue({  
  el: "#app",  
  data: {  
    text: ""  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <error-box>Error</error-box>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

The text Error that we put between the error-box tags replace the slot tag, so we get the word ‘Error’ in red displayed.

Dynamic Components

We can switch dynamically between components by using v-bind:is .

The value of v-bind:is can contain either the name of a registered component or a component’s options object.

For example, we can use it as follows:

src/index.js :

Vue.component("tab-foo", {  
  template: "<div>Foo</div>"  
});

Vue.component("tab-bar", {  
  template: "<div>Bar</div>"  
});

Vue.component("tab-baz", {  
  template: "<div>Baz</div>"  
});

new Vue({  
  el: "#app",  
  data: {  
    currentTab: "foo"  
  },  
  computed: {  
    currentTabComponent() {  
      return `tab-${this.currentTab.toLowerCase()}`;  
    }  
  }  
});

In the code above, we created 3 components, and in the root Vue instance, we have the currentTab field so that we can add buttons to change the content in the HTML template.

The currentTabComponent will be updated as this.currentTab changes, which we’ll set the value of with buttons in the template.

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <button @click='currentTab = "foo"'>Foo</button>  
      <button @click='currentTab = "bar"'>Bar</button>  
      <button @click='currentTab = "baz"'>Baz</button>  
      <component v-bind:is="currentTabComponent"></component>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

In the template above, we have 3 buttons with click event handlers to set the currentTab value, which will also set the currentTabComponent property as currentTab changes.

Since we passed currentTabComponent to v-bind:is , the component element will replace the component with the name set in currentTabComponent .

So when we click the Foo button we get Foo, when we click the Bar button we get Bar, and when we click the Baz button we get Baz.

We can pass in an object to v-bind:is as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    tabBar: {  
      template: "<div>Bar</div>"  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <component v-bind:is="tabBar"></component>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

We passed in the tabBar object as the value of v-bind:is directive.

DOM Template Parsing Issues

Some HTML elements have restrictions on what can be inside them. For example, ul must have li elements inside them.

We can nest whatever element we want with the is attribute.

For example, we can use it as follows:

src/index.js :

Vue.component("list-item", {  
  template: "<div>Foo</div>"  
});

new Vue({  
  el: "#app"  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <ul>  
        <li is="list-item"></li>  
      </ul>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

The code above sets the list-item component as the component inside the li element.

This limitation doesn’t apply if we’re using string templates from one of the following sources:

  • String templates (e.g. template: '...')
  • Single-file (.vue) components
  • <script type="text/x-template">

Conclusion

We can get the content of items in between the opening and closing tags of our component with the slot element.

The component element let us change the component dynamically by passing in a string name for the component.

We can pass an object or a string with the component name to v-bind:is .

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

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