DEV Community

Brian Neville-O'Neill
Brian Neville-O'Neill

Posted on • Originally published at blog.logrocket.com on

How to pass HTML content through components with Vue slots

This post will introduce you to how data can be passed from the parent component to child components in Vue.js using Vue slots.

Before you start…

This post is suited for developers of all stages — including beginners — though there are some prerequisites before going through this tutorial.

You will need the following on your machine:

  • Node.js version 10.x and above installed. You can verify your version by running this command in your terminal/command prompt: node -v
  • A code editor; I highly recommend Visual Studio Code
  • Vue’s latest version, installed globally on your machine
  • Vue CLI 3.0 installed on your machine. To do this, uninstall the old CLI version first: npm uninstall -g vue-cli
  • Then, install the new one: npm install -g @vue/cli
  • Download a Vue starter project here
  • Unzip the downloaded project
  • Navigate into the unzipped file and run the command to keep all the dependencies up to date: npm install

LogRocket Free Trial Banner

What are Vue slots?

Vue slots are Vue template elements created by the Vue team to provide a platform for template content distribution. It is an implementation of the a content distribution API that was inspired by the Web Components spec draft. Using Vue slots, you can pass or distribute HTML code across various components in your project.

Why are Vue slots important?

Content distribution is important for many reasons, some of which have to do with structure. With Vue slots, you can structure an HTML interface (like with TypeScript), which you can then use as a guide to build out your components by template injection. It is a very scalable and efficient solution for passing down template code from one component to another.

Positioning of content is another great use case for Vue slots. You can just create a template and then use another component or the parent component to arrange that template as you would like it to appear in the user interface.

Slots vs. props

If you know about Vue slots, you might wonder if props and slots do the same thing. Well, the central idea of these tools or platforms is to encourage reusability and efficiency of resources. With that in mind, slots and props are similar.

Props deal with passing data objects from component to component, but slots deal with passing template (HTML) content instead from component to component. However, scoped slots act exactly like props; this will be clearly illustrated in this tutorial.

Vue slot syntax

For slots, your child component acts as the interface or structure of how you want your content arranged. It can look like this:

<template>
  <div>
    <slot></slot>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

The parent component (where the HTML content to be injected into the child component resides) can look like this:

<Test>
   <h2>Hello World!</h2>
 </Test>
Enter fullscreen mode Exit fullscreen mode

This combination will return a user interface that looks like this:

<template>
  <div>
    <h2>Hello World!</h2>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Notice how the slot on it own serves as a guide for where and how content will be injected — that is the central idea.

Demo

If you have followed this post from the start, you will have the Vue starter project open in VS Code. To illustrate the simple example in the syntax section, our parent component will be the app.vue file. Open your app.vue file and copy in this code block:

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <Test>
      <h2>Hello World!</h2>
    </Test>
  </div>
</template>
<script>
import Test from './components/Test.vue'
export default {
  name: 'app',
  components: {
    Test
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

The child component is going to be the test component, so copy the code block below in the test.vue file:

<template>
  <div>
    <slot></slot>
  </div>
</template>
<script>
export default {
  name: 'Test'
}
</script>
Enter fullscreen mode Exit fullscreen mode

Run the application in the dev environment with this command:

npm run serve
Enter fullscreen mode Exit fullscreen mode

[IMAGE]

Named slots

Vue allows for more than one slot for a component, which means that you can have any number of slots you want. To test this out, copy this new code block into your test.vue file:

<template>
  <div>
    <slot></slot>
    <slot></slot>
    <slot></slot>
  </div>
</template>
<script>
export default {
  name: 'Test'
}
</script>
Enter fullscreen mode Exit fullscreen mode

If you run the application, you can see that hello world is printed three times. So if you want to add more content — say, a header, a paragraph with text, and then an unordered list — Vue lets us name the scopes so that it can identify the particular scope to display. Naming the slots in the test.vue file will look like this:

<template>
  <div>
    <slot name="header"></slot>
    <slot name="paragraph"></slot>
    <slot name="links"></slot>
  </div>
</template>
<script>
export default {
  name: 'Test'
}
</script>
Enter fullscreen mode Exit fullscreen mode

Now, you also have to label the HTML elements according to the slot name in which you want to display them. Copy this into the template section of your app.vue file:

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <Test>
      <h2 slot="header">Hello world!</h2>
      <p slot="paragraph">Hello, I am a paragraph text</p>
      <ul slot="links">
        <li>Hello, I am a list item</li>
        <li>Hello, I am a list item</li>
      </ul>
    </Test>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

[IMAGE]

V-slots syntax

When Vue version 2.6 was released, it shipped with a better syntax to reference slot names from the child components called v-slot, which is meant to replace the initial slot syntax. So, instead of a parent component template with slots like this:

<Test>
   <h1 slot="header">Hello world!</h1>
</Test>
Enter fullscreen mode Exit fullscreen mode

From version 3.0 (which should be released before the end of the year), it will now look like this:

<Test v-slot:header>
   <h1>Hello world!</h1>
</Test>
Enter fullscreen mode Exit fullscreen mode

Notice that aside from the minor change in the string from slot to v-slot, there is also a major change: the v-slot can only be defined on templates instead of on any HTML element. This is a big change as it questions the usability of named slots, but as of this writing, slots are still very much part of the documentation.

Scoped slots

Imagine a scenario in which the Vue slot can also access the data object in the child component from the parent component — a kind of slot with props ability. To illustrate this, go ahead and create a data object in the child component by copying the code block below into the test.vue file:

<template>
  <div>
    <slot v-bind:team="team"></slot>
    <slot name="paragraph"></slot>
    <slot name="links"></slot>
  </div>
</template>
<script>
export default {
  name: 'Test',
  data(){
    return{
      team:"FC Barcelona"
    }
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

Just like normal props, the v-bind directive was used to bind the team in the data with the prop reference in the parent component. Open your app.vue file and copy the code block below into the template section:

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <Test v-slot="{team}">
      <h2>Hello world! my team is {{team}}</h2>
    </Test>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

If you run your application, you will see that the data object was successfully passed to the parent component. You can find the complete code for this tutorial here.

Conclusion

This post has introduced you to slots in Vue.js and how they are important to content injection. You saw how to set it up, and even how to have more than one slot for a component. You also saw how slots can also act as props by scoping. Go ahead and enjoy implementing slots in your workflow.


Plug: LogRocket, a DVR for web apps

 
LogRocket Dashboard Free Trial Banner
 
LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
Try it for free.


The post How to pass HTML content through components with Vue slots appeared first on LogRocket Blog.

Top comments (0)