DEV Community

Cover image for Crafting Easy-to-Use Components with Vue.js v-slot Magic
WebCraft Notes
WebCraft Notes

Posted on • Updated on • Originally published at webcraft-notes.com

Crafting Easy-to-Use Components with Vue.js v-slot Magic

Check this post in my web notes.

In our previous tutorials, we've explored an array of functionalities within Vue.js: from crafting modals, notifications, and tabs to managing validation and optimizing image uploads for servers. Amidst this array lies a suite of magical tools within Vue.js that empower these functionalities. Today, we're diving deeper into one such tool that holds immense power in Vue.js development: 'v-slot.' This tool enables the creation of versatile and dynamic functionalities, and in this post, we're delving into the intricate world of 'v-slot' and its transformative capabilities.

Step 1: Initial Project Setup

We will create a Vue js project using Quick Start instructions from Vue js official documentation.
Execute the following command to create a vite project:

npm create vue@latest

This command will install and execute create-vue, the official Vue project scaffolding tool.

Once executed, you will be asked some questions.
vue.js starting question
If you are unsure about an option, simply choose "No" by hitting enter for now. Once the project is created, follow the instructions to install dependencies and start the dev server:
start vue.js dev server
Now you should visit the offered "localhost:" route, and you'll see the initial project. You can remove all components and styles we will not need.

Step 2: Content slot and insertion point

Most common way of communication between components that we already know about is "props": data that we can pass from parent to child component. By using props we can set, update, and remove data in a child component or even call a function, what else can we dream about? What "Slots" can offer to us? Slots can give us easy access to the child template, so we could send a template fragment from the parent component to the child and the child component will render it for us, we can also update that fragment dynamically.
Let's check how it works on a simple example. First of all, we will create two components that will represent "parent" and "child".

<template>
  <div class="container">
    <div class="center">
      <Tabs>
        <h3 class="header">First Tab</h3>
        <div class="img-container">
          <img src="https://cdn.pixabay.com/photo/2023/11/25/15/45/mountains-8411954_1280.jpg" />
        </div>
      </Tabs>
    </div>
  </div>
</template>

<script>
import Tabs from "@/components/Tabs.vue";
export default {
  name: "App",
  components: {
    Tabs
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

Here is our Main App.vue component, where we import the "child" component Tabs.vue and add "slot content" inside. So that our "slot content" will be auto-injected into the "slot outlet" in the Tabs component.

<template>
    <div class="tabs">
        <slot></slot>
    </div>
</template>

<script>
export default {
    name: "Tabs"
}
</script>
Enter fullscreen mode Exit fullscreen mode

In our child component "" is the place where our slot content will be injected. As the result, we will have something like this:
first result
All that window is our container and white space is our "slot" where we inject template fragment that contains the header and image. So we just briefly considered v-slot functionality but it's too early to stop.

Step 3. Named Slots

Okay, what to do if we want to add a few different slots in one component? We only need to use "Named Slots". Let's check how to do it in our next example.
Our App.vue file:

<template>
  <div class="container">
    <div class="center">
      <Tabs v-slot:firstTab>
        <h3 class="header">First Tab</h3>
        <div class="img-container">
          <img src="https://cdn.pixabay.com/photo/2023/11/25/15/45/mountains-8411954_1280.jpg" />
        </div>
      </Tabs>
      <Tabs v-slot:secondTab>
        <h3 class="header">Second Tab</h3>
        <div class="img-container">
          <img src="https://cdn.pixabay.com/photo/2023/04/21/17/47/plum-blossoms-7942343_640.jpg" />
        </div>
      </Tabs>
    </div>
  </div>
</template>

<script>
import Tabs from "@/components/Tabs.vue";
export default {
  name: "App",
  components: {
    Tabs
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

We only added the same Tabs.vue fragment into the template and more important we added a "name" attribute with a unique identifier. Now we need to add slot outlet to our child component with a unique identifier from App.vue.

<template>
    <div class="tabs">
        <slot name="firstTab"></slot>
        <slot name="secondTab"></slot>
    </div>
</template>

<script>
export default {
    name: "Tabs"
}
</script>
Enter fullscreen mode Exit fullscreen mode

And our second result:
second result
These name attributes determine the correspondence between slot content and outlet.
Okay, that's cool but where is the magic?

Step 4. Magic

As for me the biggest interest for us in "Slots" it's dynamism. We can update template fragments dynamically as a response to some event for example. Let's check few variants:

<template>
  <div class="container">
    <div class="center">
      <Tabs v-slot:[tab1]>
        <h3 class="header">First Tab</h3>
        <div class="img-container">
          <img src="https://cdn.pixabay.com/photo/2023/11/25/15/45/mountains-8411954_1280.jpg" />
        </div>
      </Tabs>
      <Tabs v-slot:[tab2]>
        <h3 class="header">Second Tab</h3>
        <div class="img-container">
          <img src="https://cdn.pixabay.com/photo/2023/04/21/17/47/plum-blossoms-7942343_640.jpg" />
        </div>
      </Tabs>
    </div>
  </div>
</template>

<script>
import Tabs from "@/components/Tabs.vue";
export default {
  name: "App",
  components: {
    Tabs
  },
  data() {
    return {
      tab1: 'firstTab',
      tab2: 'secondTab'
    }
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

Continue reading...

Top comments (0)