Composing Svelte Components with Slots

John Au-Yeung - Jan 28 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Svelte is an up and coming front end framework for developing front end web apps.

It’s simple to use and lets us create results fast.

In this article, we’ll look at how to nest Svelte components with slots.

Component Composition

We can add the slot component to a Svelte component to let us nest components inside another component.

For example, we can use the slot component as follows:

App.svelte :

<script>
import Parent from "./Parent.svelte";
import Foo from "./Foo.svelte";
</script>

<Parent>
  <Foo />
</Parent>
Enter fullscreen mode Exit fullscreen mode

Parent.svelte :

<div>
  <p>Start</p>
  <p>
    <slot></slot>
  </p>
  <p>End</p>
</div>
Enter fullscreen mode Exit fullscreen mode

Foo.svelte :

<button>
  foo
</button>
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the Parent component, which has the slot component, which lets us nest one or more components inside it.

Parent has 3 p elements. The slot is in the 2nd p element.

We created the Foo component with a button. Then when we write:

<Parent>
  <Foo />
</Parent>
Enter fullscreen mode Exit fullscreen mode

in App.svelte , we’ll see the button displayed between ‘start’ and ‘end’.

Fallback Content

We can put fallback content in between the slot tags so that when we didn’t pass in anything in between the tags of the component with the slot component, then we’ll still see something displayed.

For example, we can write the following code to add fallback content and display it:

App.svelte :

<script>
import Parent from "./Parent.svelte";
</script>

<Parent />
Enter fullscreen mode Exit fullscreen mode

Parent.svelte :

<div>
  <p>Start</p>
  <p>
    <slot>
      <p>Nothing to see here</p>
    </slot>
  </p>
  <p>End</p>
</div>
Enter fullscreen mode Exit fullscreen mode

In the code above, we have:

<p>Nothing to see here</p>
Enter fullscreen mode Exit fullscreen mode

in between the slot tags. Then when we write <Parent /> as we did in App.svelte , we’ll see:

Start

Nothing to see here

End
Enter fullscreen mode Exit fullscreen mode

displayed on the screen since we used a self-closing version of Parent instead of passing child elements in between the tags.

Multiple Slots with Named Slots

We can add multiple slots by naming the slots. Then we can add content for each slot with the slot attribute with the name of the slot as the value.

For instance, we can write the following code to add multiple slots and populate them with content:

Contact.svelte :

<article>
  <h2>
    <slot name="name">
      <span>No name</span>
    </slot>
  </h2>

  <div class="address">
    <slot name="address">
      <span>No address</span>
    </slot>
  </div>

  <div class="email">
    <slot name="email">
      <span>No email</span>
    </slot>
  </div>
</article>
Enter fullscreen mode Exit fullscreen mode

App.svelte

<script>
import Contact from "./Contact.svelte";
</script>

<Contact>
  <span slot="name">
    Jane Smith
  </span>

  <span slot="address">
    123 A St.
  </span>

  <span slot="email">
    abc@abc.com
  </span>
</Contact>
Enter fullscreen mode Exit fullscreen mode

In the code above, we defined multiple slots with the name attribute added to each in Contact.svelte .

Then we can use the Contact component in App.svelte when we pass in components into each slot as identified by their names. Therefore, we should see:

Jane Smith

123 A St.
abc@abc.com
Enter fullscreen mode Exit fullscreen mode

displayed on the screen.

Passing Child Data to Parent Component via Slots

We can use slot props to pass data from the child component to the parent component. To define slot props, we set the prop name with the variable that we want to pass to the parent as the value.

To define slot props and use it, we can write the following code:

Contact.svelte :

<script>
let names = ["John", "Jane", "Mary"];
</script>

<article>
  <slot names={names}></slot>
</article>
Enter fullscreen mode Exit fullscreen mode

The code above has the slot prop names , which we pass the names variable into it.

Then we can use it in App.svelte as follows:

<script>
import Contact from "./Contact.svelte";
</script>

<Contact let:names={names}>
  {#each names as name}
    <p>{name}</p>
  {/each}
</Contact>
Enter fullscreen mode Exit fullscreen mode

The let directive defines the slot prop variable, which should have the slot prop as the value.

In the code above, let:names={names} sets the slot props with the names prop from Contact as the value for the names variable in App.svelte .

Then we can access names inside the loop as we did in the each loop.

Therefore, we should get:

John

Jane

Mary
Enter fullscreen mode Exit fullscreen mode

displayed on the screen.

Named slots can also have props. We can write:

Contact.svelte :

<script>
let contactName = "Jane Smith";
let address = "123 A. St";
let email = "abc@abc.com";
</script>

<article>
  <h2>
    <slot name="name" contactName={contactName}>
      <span>No name</span>
    </slot>
  </h2>
  <div class="address">
    <slot name="address" address={address}>
      <span>No address</span>
    </slot>
  </div>
  <div class="email">
    <slot name="email" email={email}>
      <span>No email</span>
    </slot>
  </div>
</article>
Enter fullscreen mode Exit fullscreen mode

App.svelte :

<script>
import Contact from "./Contact.svelte";
</script>

<Contact>
  <span slot="name" let:contactName={contactName}>
    {contactName}
  </span>
  <span slot="address" let:address={address}>
    {address}
  </span>
  <span slot="email" let:email={email}>
    {email}
  </span>
</Contact>
Enter fullscreen mode Exit fullscreen mode

In the code above, we defined slot props for each slot, and then pass them into the App.svelte component with the let directive as we did with the single slot example.

Therefore, we should have:

Jane Smith

123 A St.
abc@abc.com
Enter fullscreen mode Exit fullscreen mode

displayed as we did with the earlier example.

Conclusion

We can use slots to nest components within another component. To pass data from the child components to the parent, we can use slot props.

Slot props are defined with the let directive. The value of it should be the variable name to reference the slot prop value. Then we can access the slot prop value in between the tags.

Fallback content can be added between the slot tags and they’re displayed and we reference a component with a self-closing tag.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .