How to pass children elements in Svelte with slot
Are you trying to figure out how to pass children elements to a Svelte component? Or maybe passing another Svelte component inside Svelte component?
The answer is really simple. To pass any element down to a Svelte component you must use the <slot>
HTML directive that Svelte provides.
Let’s dive into how to do accomplish this with <slot>
Solution: Use <slot>
To pass elements down to a Svelte component, you must use the <slot>
HTML directive.
First let’s create a Svelte component called Nested
.
<!-- Nested.svelte -->
<div class="container">
<slot></slot>
</div>
<style>
.container {
height: 300px;
justify-content: center;
display: flex;
align-items: center;
}
</style>
As you can see above, all prop children elements will be inside a .container
.
Now I will use the Nested
Svelte component inside the App
Svelte component and pass an h1
element.
<!-- App.svelte -->
<script>
// Import Nested.svelte component
import Nested from './Nested.svelte';
</script>
<Nested>
<h1>Hello World!</h1>
</Nested>
<style>
h1 {
color: #ff0000;
font-weight: 300;
font-size: 64px;
}
</style>
That’s it!
The <slot>
element lets Svelte know where children elements should be placed.
The example above demonstrates passing native HTML element, but can we have nested Svelte components?
You can pass svelte components to another Svelte components
You may pass multiple components <slot>
.
<!-- App.svelte -->
<script>
import Nested from './Nested.svelte';
</script>
<Nested>
<Nested>
<p>Double nested components</p>
</Nested>
</Nested>
But what if you don’t pass any children elements to the component? What happens then?
Add a <slot>
fallback option
If you’d like, you can add a fallback option in case no children elements or Svelte components get tossed down.
Let’s update the Nested.svelte file to allow a fallback option.
<!-- Nested.svelte -->
<div class="container">
<slot>
<h1>The Nested.svelte component is empty!</h1>
</slot>
</div>
Inside the <slot>
element, you can add whatever you want to display as a fallback option.
Let’s update the App.svelte file
<!-- App.svelte -->
<script>
import Nested from './Nested.svelte';
</script>
<!-- Will NOT display fallback option -->
<Nested>
</Nested>
<!-- Will display fallback option -->
<Nested />
As shown above, if you have open and close tags for your component, Svelte will take that emptiness as children being passed down. Which will not display the fallback option.
To display the fallback option, the component has to be written in short-hand version.
Composing <slot>
AKA create multiple <slot>
You may be wondering, can I create multiple <slot>
locations in a Svelte component?
The answer is, yes you can! This is accomplished by giving a name to the <slot>
element.
<!-- Nested.svelte -->
<div class="container">
<div>
<slot name="header"></slot>
<slot name="subheader"></slot>
</div>
</div>
<style>
.container {
height: 300px;
justify-content: center;
display: flex;
align-items: center;
text-align: center;
}
</style>
The <slot>
directive accepts an attribute called name
.
The value will be our label for that specific <slot>
directive.
Now let’s update the parent Svelte component and make use of our new slot elements.
<!-- App.svelte -->
<script>
import Nested from './Nested.svelte';
</script>
<Nested>
<h1 slot="header">Hello World!</h1>
<h2 slot="subheader">Say hi back please!</h2>
</Nested>
<!-- Reversed -->
<Nested>
<h1 slot="subheader">Hello World!</h1>
<h2 slot="header">Say hi back please!</h2>
</Nested>
<style>
h1 {
color: #ff0000;
font-weight: 300;
font-size: 64px;
}
</style>
To attach a child element to a slot , you must also add the attribute name, slot
, and give it the placeholder value that you wrote in your sub component.
Let’s take a look at an example of trying to group child elements into the same slot label. FYI this will break your Svelte app.
<Nested>
<h1 slot="header">Hello World!</h1>
<h2 slot="header">I wanna be part of the same slot label</h2>
<div slot="subheader">
<p>This is a small description about this page. hi!</p>
</div>
</Nested>
If you wanted to group multiple elements in the same slot
label, you must use svelte:fragment
.
Use svelte:fragment
to group elements in the same named slot
Use svelte:fragment
to group elements in the same named slot without wrapping a container DOM element.
<Nested>
<svelte:fragment slot="header">
<h1>Hello World!</h1>
<h2>I wanna be part of the same slot label</h2>
</svelte:fragment>
<div slot="subheader">
<p>This is a small description about this page. hi!</p>
</div>
</Nested>
Slot is a reserved keyword
The keyword slot is a reserved name in Svelte and cannot be used an attribute to any element.
You CANNOT do this:
<Nested>
<Nested slot="header">Hello World!</nested>
<Nested slot="subheader">Say hi back please!</nested>
</Nested>
Svelte components can only go in <slot>
elements that don’t have the attribute, name
.
How to check if a slot is present or it exists?
Another question I had about <slot> was, can I check if content is being passed down? Why render HTML if the slot is empty. For example, let’s take a look at the original slot code example:
<div class="container">
<slot></slot>
</div>
Let’s say, I don’t want to render an empty div element if content is not being given. How do I put an IF
condition?
It turns out that Svelte gives you access to a special variable called $$slots
.
{#if $$slots.default}
<div class="container">
<slot />
</div>
{/if}
And if you have multiple named slots, it will add those names as properties inside the $$slot
object. For example:
{#if $$slots.title}
<div class="title">
<h1>
<slot name="title" />
</h1>
</div>
{/if}
{#if $$slots.description}
<div class="description">
<h1>
<slot name="desc" />
</h1>
</div>
{/if}
Hey, you’ve made it this far! If you found this article helpful, I would appreciate it if you liked or retweet the tweet below!
I like to tweet about Svelte and post helpful code snippets. Follow me there if you would like some too!