Skip to main content

Part 3 / Component composition / Checking for slot content

The images in this exercise don't currently work. You can switch to the old tutorial instead: https://svelte.dev/tutorial/optional-slots

In some cases, you may want to control parts of your component based on whether the parent passes in content for a certain slot. Perhaps you have a wrapper around that slot, and you don't want to render it if the slot is empty. Or perhaps you'd like to apply a class only if the slot is present. You can do this by checking the properties of the special $$slots variable.

$$slots is an object whose keys are the names of the slots passed in by the parent component. If the parent leaves a slot empty, then $$slots will not have an entry for that slot.

Notice that both instances of <Project> in this example render a container for comments and a notification dot, even though only one has comments. We want to use $$slots to make sure we only render these elements when the parent <App> passes in content for the comments slot.

In Project.svelte, update the class:has-discussion directive on the <article>:

<article class:has-discussion={$$slots.comments}>

Next, wrap the comments slot and its wrapping <div> in an if block that checks $$slots:

{#if $$slots.comments}
	<div class="discussion">
		<h3>Comments</h3>
		<slot name="comments"></slot>
	</div>
{/if}

Now the comments container and the notification dot won't render when <App> leaves the comments slot empty.

Next: Slot props

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<script>
	import Project from './Project.svelte';
	import Comment from './Comment.svelte';
</script>
 
<h1>Projects</h1>
 
<ul>
	<li>
		<Project
			title="Add Typescript support"
			tasksCompleted={25}
			totalTasks={57}
		>
			<div slot="comments">
				<Comment
					name="Ecma Script"
					postedAt={new Date(
						'2020-08-17T14:12:23'
					)}
				>
					<p>
						Those interface tests are now passing.
					</p>
				</Comment>
			</div>
		</Project>
	</li>
	<li>
		<Project
			title="Update documentation"
			tasksCompleted={18}
			totalTasks={21}
		/>
	</li>
</ul>
 
<style>
	h1 {
		font-weight: 300;
		margin: 0 1rem;
	}
 
	ul {
		list-style: none;
		padding: 0;
		margin: 0.5rem;
		display: flex;
	}
 
	@media (max-width: 600px) {
		ul {
			flex-direction: column;
		}
	}
 
	li {
		padding: 0.5rem;
		flex: 1 1 50%;
		min-width: 200px;
	}
</style>
 
initialising