Categories
Vue 3

Vue 3 — Slot Shorthands

Spread the love

Vue 3 is in beta and it’s subject to change.

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at slot shorthands with Vue 3.

Shorthand Syntax for Default Slots

If we have one slot, then we don’t need the template element.

We can put the v-slot directive right on the opening component tag.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <items v-slot="slotProps">
        <b>{{ slotProps.item.name }}</b>
      </items>
    </div>
    <script>
      const app = Vue.createApp({});

      app.component("items", {
        template: `
          <ul>
            <li v-for="( item, index ) in items">
              <slot v-bind:item="item"></slot>
            </li>
          </ul>
        `,
        data() {
          return {
            items: [{ name: "apple" }, { name: "orange" }, { name: "grape" }]
          };
        }
      });

      app.mount("#app");
    </script>
  </body>
</html>

We have the v-slot directive on the component tag, which is only allowed when we have one slot in our component.

Destructuring Slot Props

Slot props can be destructured.

Since we have an object as the value of v-slot , we can destructure its properties.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <items v-slot="{ item: { name } }">
        <b>{{ name }}</b>
      </items>
    </div>
    <script>
      const app = Vue.createApp({});

      app.component("items", {
        template: `
          <ul>
            <li v-for="( item, index ) in items">
              <slot v-bind:item="item"></slot>
            </li>
          </ul>
        `,
        data() {
          return {
            items: [{ name: "apple" }, { name: "orange" }, { name: "grape" }]
          };
        }
      });

      app.mount("#app");
    </script>
  </body>
</html>

We destructured the properties of the slotProps object, so instead of writing:

<items v-slot="slotProps">
  <b>{{ slotProps.item.name }}</b>
</items>

we have:

<items v-slot="{ item: { name } }">
  <b>{{ name }}</b>
</items>

This can make templates much cleaner especially if we have many slots.

It’s also easy for us to provide fallbacks.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <items v-slot="{ item: { name = 'placeholder' } }">
        <b>{{ name }}</b>
      </items>
    </div>
    <script>
      const app = Vue.createApp({});

      app.component("items", {
        template: `
          <ul>
            <li v-for="( item, index ) in items">
              <slot v-bind:item="item"></slot>
            </li>
          </ul>
        `,
        data() {
          return {
            items: [{ name: "apple" }, { name: "orange" }, {}]
          };
        }
      });

      app.mount("#app");
    </script>
  </body>
</html>

We set the default value of the name property to 'placeholder' so that we can display that if nothing is set for the name property.

Dynamic Slot Names

Slot names can be dynamic.

So we can write:

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</base-layout>

where dynamicSlotName is the variable with the slot name.

Named Slots Shorthand

Named slots can be shorted with the # sign.

For example, instead of writing:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <blog-post>
        <template v-slot:header>
          <h1>header</h1>
        </template>
        <template v-slot:default>
          <p>lorem ipsum.</p>
        </template>
        <template v-slot:footer>
          <p>footer</p>
        </template>
      </blog-post>
    </div>
    <script>
      const app = Vue.createApp({});
      app.component("blog-post", {
        template: `
          <header>
            <slot name="header"></slot>
          </header>
          <main>
            <slot></slot>
          </main>
          <footer>
            <slot name="footer"></slot>
          </footer>
        `
      });
      app.mount("#app");
    </script>
  </body>
</html>

We can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <blog-post>
        <template #header>
          <h1>header</h1>
        </template>
        <template #default>
          <p>lorem ipsum.</p>
        </template>
        <template #footer>
          <p>footer</p>
        </template>
      </blog-post>
    </div>
    <script>
      const app = Vue.createApp({});
      app.component("blog-post", {
        template: `
          <header>
            <slot name="header"></slot>
          </header>
          <main>
            <slot></slot>
          </main>
          <footer>
            <slot name="footer"></slot>
          </footer>
        `
      });
      app.mount("#app");
    </script>
  </body>
</html>

# is short for v-slot: .

Conclusion

There’s a shorthand for named slots and also there’s a shorthand for default slots.

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 *