A comprehensive guide to Svelte components with slots

Introduction

One way of creating a reusable component is by passing children elements or components to parent components. With UI libraries like React, we can create reusable components with React’s children prop. But how can we handle passing child data to parent components in Svelte?

In come Svelte slots. We can use Svelte slots to create components that accept and render any children. This way, we will be able to create components that can be used multiple times in our application. Slots are useful because they help keep our codebase DRY. Slots also make maintaining, debugging, and updating components easier.

In this article, we will learn how to compose reusable Svelte components with slots, including the different ways we can use them by looking at some practical code examples.

Using Svelte slots

Let’s see how slots work in practice:

<div class="card">
  <h1>I am a reusable box</h1>
  <slot></slot>
</div>

<style>
  .card {
    width: 300px;
    border: 1px solid #aaa;
    border-radius: 2px;
    box-shadow: 2px 2px 8px rgba(0,0,0,0.1);
    padding: 1em;
    margin: 0 0 1em 0;
  }
</style>

In the code above, we created a Card component. The slot component allows us to pass child data and content to the Card component, thereby making it reusable.

We can use the Card component in App.svelte and pass in our content:

<script>
  import Card from './Card.svelte';
</script>

<Card>
  <h1>Hello!</h1>
  <p>This is a box. It can contain anything.</p>
</Card>

Slot fallbacks

We can add fallback content to slots to act as placeholders when the slots are empty.

Say we create a blog post card component. We may want to add a fallback title to each post until the cards receive the actual data. We can do that with slot fallbacks.

Whatever data we pass between the opening and closing tags of the slot component will be the fallback content:

    <!-- Card.svelte -->
    <div class="card">
      <slot>
        <h1>Fallback Blog Title</h1>
      </slot>
    </div>
    
    <!-- App.svelte -->
    
    <script>
      import Card from "./Card.svelte";
    </script>
    <Card />

This way, every blog card we have will have the generic “Fallback Blog Title” heading until we pass in the actual data. Slot fallbacks are also useful if you need to set up dummy data for your components while developing.

Named slots

We can have multiple slots in a Svelte component by using the name attribute on the slot component.

Let’s assume we want to extend the blog card component. Most blog cards don’t have only titles, they also also have dates and a section with some details of what the post is about.

Let’s set this in different sections of the blog card:

<section>
  <slot name="title" />
  <slot name="date"/>
  <slot name="content" />
</section>

Here, we composed the Card component to a blog card using slots. To do that, we set up two named slots, title and content.

We used the Card component in App.svelte. Then, we looped through the items array and passed in the title, date and content data to their respective slots like so:

<script>
  import Card from "./Card.svelte";
  const items = [
    {title: "Title 1", date: '1-06-2000', content: "Some content content here"},
    {title: "Title 2", date: '1-06-2000', content: "Some more content content here"},
  ];
</script>

{#each items as item}
  <Card>
    <h1 slot="title">{item.title}</h1>
    <span slot="date">{item.date}</span>
    <p slot="content">{item.content}</p>
  </Card>
{/each}

Named slots and Svelte fragments

How do we go about passing multiple components into a named slot? Say we want to create a card header slot with a title and date, how would we do that?

Let’s look at how to handle the following scenario:

<Card>
  <slot="header">card title</slot>
  <slot="header">card date</slot>
</Card>
<!-- ❗ Duplicate slot name "header" in <Card> -->

The code above will not work because because duplication of slot names is not allowed. How can we fix it?

The solution lies in using a special Svelte element, Svelte:fragment. svelte:fragment allows you to place content in a named slot without wrapping it in a container DOM element. This keeps the flow layout of your document intact.

Let’s refactor the Card component with svelte:fragment:

<Card>
  <svelte:fragment slot="header">
    <h1>Card title</h1>
    <p>Card date</p>
  </svelte:fragment>
</Card>

With svelte:fragment, we avoid adding needless HTML elements that can affect the layout and styling.

Conditionally display slots

There are times where we may not want to set fallback content for slots, yet want to ensure a slot only renders when there is content in it.

We can do that with the special $$slots variable. While this may not be a critical feature to add, it can affect the styling and layout of your application if a component renders when it’s not supposed to.

Let’s ensure the Card component does not have empty slots before rendering it like so:

<div class="card">
  {#if $$slots.title}
    <slot name="title" />
  {/if}

  {#if $$slots.content}
    <slot name="content">Content</slot>
  {/if}
</div>

Aside from conditionally rendering slot components, we can also use the $$slots variable to conditionally apply classes to components:

<div class="card">
  <slot name="title" class:title-style={$$slots.title} />

  {#if $$slots.content}
    <slot name="content">Content</slot>
  {/if}
</div>

<style>
  .title-style{
    color: red;
  }
</style>

The $$slots variable is an object whose keys are the names of the slots passed in by the parent component, and we can use it to conditionally display or style slot components.

Passing data across slots through props

We can use slot props to pass data from the child to parent using the let: directive of slots. This helps us set up separation of concerns between the parent and the child component.

Say we have an array of employees we want to render in our UI. We set up a Contacts.svelte component where the employees’ details will be rendered, and call Contacts.svelte in App.svelte.

We could store the employees’ data in our App.svelte file, however, we want to avoid polluting App.svelte with data it does not need, as this will make it harder to maintain in the future.

Let’s set this up in our code and see how it works:

<!--Contacts.svelte -->
<script>
  const names = ["John", "Jane", "Mary"];
</script>

<div class="contact">
  <slot {names} />
</div>

<!--App.svelte -->
<script>
  import Card from "./Card.svelte";
</script>

<Contacts let:names>
  {#each names as name}
    <p>{name}</p>
  {/each}
</Contacts>

With this, we can leave the responsibility of handling local state and data to the child component, Contacts.svelte, and keep our App.svelte cleaner.

We can also pass data through named slots, like so:

<!--Card.svelte -->
<script>
  let title = "I am the title";
  let content = "I am the content";
</script>

<div class="card">
  <slot name="title" {title} />
  <slot name="content" {content} />
</div>


<!--App.svelte -->
<script>
  import Card from "./Card.svelte";
</script>

<Card>
  <h1 slot="title" let:title>{title}</h1>
  <p slot="content" let:content>{content}</p>
</Card>

Conclusion

In this article, we have learned how to compose Svelte components with slots. We learned what slots are, how to set up fallback content, and named slots. We also learned how to pass dynamic data to slots through props. Asides from the features of slots, we also looked at some scenarios and how they can be used practically.

Now that you have learned about Svelte slots, I encourage you to dive into the docs, practice, and build some awesome applications.

The post A comprehensive guide to Svelte components with slots appeared first on LogRocket Blog.

This article was republished from its original source.
Call Us: 1(800)730-2416

Pixeldust is a 20-year-old web development agency specializing in Drupal and WordPress and working with clients all over the country. With our best in class capabilities, we work with small businesses and fortune 500 companies alike. Give us a call at 1(800)730-2416 and let’s talk about your project.

FREE Drupal SEO Audit

Test your site below to see which issues need to be fixed. We will fix them and optimize your Drupal site 100% for Google and Bing. (Allow 30-60 seconds to gather data.)

Powered by

A comprehensive guide to Svelte components with slots

On-Site Drupal SEO Master Setup

We make sure your site is 100% optimized (and stays that way) for the best SEO results.

With Pixeldust On-site (or On-page) SEO we make changes to your site’s structure and performance to make it easier for search engines to see and understand your site’s content. Search engines use algorithms to rank sites by degrees of relevance. Our on-site optimization ensures your site is configured to provide information in a way that meets Google and Bing standards for optimal indexing.

This service includes:

  • Pathauto install and configuration for SEO-friendly URLs.
  • Meta Tags install and configuration with dynamic tokens for meta titles and descriptions for all content types.
  • Install and fix all issues on the SEO checklist module.
  • Install and configure XML sitemap module and submit sitemaps.
  • Install and configure Google Analytics Module.
  • Install and configure Yoast.
  • Install and configure the Advanced Aggregation module to improve performance by minifying and merging CSS and JS.
  • Install and configure Schema.org Metatag.
  • Configure robots.txt.
  • Google Search Console setup snd configuration.
  • Find & Fix H1 tags.
  • Find and fix duplicate/missing meta descriptions.
  • Find and fix duplicate title tags.
  • Improve title, meta tags, and site descriptions.
  • Optimize images for better search engine optimization. Automate where possible.
  • Find and fix the missing alt and title tag for all images. Automate where possible.
  • The project takes 1 week to complete.