Categories
JavaScript Vue

How to create more complex slots in Vue

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 named and scoped slots.

Named Slots

Sometimes we want to have multiple slots. To distinguish them, then we have to name them.

We can define a component with named slots with the name attribute as follows:

Vue.component("layout", {  
  template: `  
  <div>  
    <header>      
      <slot name="header"></slot>  
    </header>  
    <main>        
      <slot></slot>  
    </main>  
    <footer>        
      <slot name="footer"></slot>  
    </footer>  
  </div>  
  `  
});

Then we can use the component above together as follows:

src/index.js :

Vue.component("layout", {  
  template: `  
  <div>  
    <header>      
      <slot name="header"></slot>  
    </header>  
    <main>        
      <slot></slot>  
    </main>  
    <footer>        
      <slot name="footer"></slot>  
    </footer>  
  </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">  
      <layout>  
        <template v-slot:header>  
          <h1>Header</h1>  
        </template> <p>Main</p> <template v-slot:footer>  
          <p>Footer</p>  
        </template>  
      </layout>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

The slot with the name header is filled with:

<template v-slot:header>  
   <h1>Header</h1>  
</template>

The slot with the name footer is filled with:

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

The slot with no name is filled with:

<p>Main</p>

If we want to wrap the content for the slot with no name with v-slot:default as follows:

<template v-slot:default>  
  <p>Main</p>  
</template>

Either way, the rendered HTML will be the same.

Scoped Slots

We can use scoped slots to access data from the child component.

To make data from the child component available in the parent, we can use the v-bind directive.

A simple example, to get child component data from the parent would be as follows:

src/index.js :

Vue.component("user", {  
  data() {  
    return {  
      user: {  
        firstName: "Joe",  
        lastName: "Smith"  
      }  
    };  
  },  
  template: `<p>  
    <slot v-bind:user="user"></slot>  
  </p>`  
});

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">  
      <user>  
        <template v-slot:default="slotProps">  
          {{ slotProps.user.firstName }}  
        </template>  
      </user>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, we have:

<p>  
   <slot v-bind:user="user"></slot>  
</p>

to make user available from within the root Vue instance.

Then in the root template, we have:

<user>  
  <template v-slot:default="slotProps">  
    {{ slotProps.user.firstName }}  
  </template>  
</user>

to access user ‘s data via slotProps slotProps have access to all the data that are made available via v-bind in the child component.

Abbreviated Syntax for Lone Default Slots

If there’s only the default slot with provided content, we can shorten v-slot:default or v-slot on the component as follows:

<user v-slot:default="slotProps">  
   {{ slotProps.user.firstName }}  
</user>

or:

<user v-slot="slotProps">  
   {{ slotProps.user.firstName }}  
</user>

If there’re other named slots, then the syntax above can’t be used because of potential ambiguity.

If we have multiple slots, then we have to write something like the following:

src/index.js :

Vue.component("user", {  
  data() {  
    return {  
      user: {  
        firstName: "Joe",  
        lastName: "Smith"  
      }  
    };  
  },  
  template: `<p>  
    <slot v-bind:user="user" name='first-name'></slot>  
    <slot v-bind:user="user" name='last-name'></slot>  
  </p>`  
});

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">  
      <user>  
        <template v-slot:first-name="slotProps">  
          {{ slotProps.user.firstName }}  
        </template>  
        <template v-slot:last-name="slotProps">  
          {{ slotProps.user.lastName }}  
        </template>  
      </user>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, we have to name the slots explicitly, and then we can access the child component’s data via v-slot:first-name=”slotProps” and v-slot:last-name=”slotProps” respectively.

Also, we wrapped the slot content in template .

Destructuring Slot Props

We can destructure the properties of the slot props with the destructuring assignment operator.

For example, we can use it as follows:

src/index.js :

Vue.component("user", {  
  data() {  
    return {  
      user: {  
        firstName: "Joe",  
        lastName: "Smith"  
      }  
    };  
  },  
  template: `<p>  
    <slot v-bind:user="user" name='first-name'></slot>  
    <slot v-bind:user="user" name='last-name'></slot>  
  </p>`  
});

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">  
      <user>  
        <template v-slot:first-name="{ user }">  
          {{ user.firstName }}  
        </template>  
        <template v-slot:last-name="{ user }">  
          {{ user.lastName }}  
        </template>  
      </user>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, instead of writing slotProps , we changed it to { user } . { user } is the same as slotProps.user .

Conclusion

We can use named and scoped slots to create multiple slots and access data from the child component in the parent respectively.

Named slots prevent ambiguity and lets us use multiple slots.

Also, we can use v-bind in the child component and then use slotProps in the component to access child component’s data from the parent component.

Leave a Reply

Your email address will not be published.

If you like the content of this blog, subscribe to my email list to get exclusive articles not available to anyone else.