Composition in Svelte 3: slots
Tags: svelte, javascript, webdev
Published: 2020-03-21 14:20:16

## Table Of Contents
* [Slots](#chapter-slots)
* [Slot fallback](#chapter-slot-fallback)
* [Named slots](#chapter-named-slots)
* [Slot props](#chapter-slot-props)

Composition is a powerful tool that allows you to create complex application functionality by combining small and easily manageable components. To achieve composition in Svelte 3, you have to use a **slot** directive.

### Slots <a name="chapter-slots"></a>
As a normal html element, a svelte 3 component can have some child content.You can pass any valid html data inside a component, and it will be rendered inside a **slot** directive:

####Box.svelte
```html
<style>
	.box {
		width: 250px;
		border: 1px solid #aaa;
		padding: 1em;
		margin: 1em;
		display: inline-block;
	}
</style>

<div class="box">
    <slot></slot>
</div>
```

```html
<script>
    import Box from "./Box.svelte";
</script>

<Box>
	<h1>Hello World</h1>
	<p>Some paragraf</p>
</Box>
```
As the result you will have a box with a header and paragraph inside of a box.

### Slot fallback <a name="chapter-slot-fallback"></a>
Slot allows you to define some custom content that will be shown if there is no child content:

####SlotWithFallback.svelte
```html
<slot>
    <h2>There is no child content!</h2>
</slot>
```
####App.svelte
```html
<script>
    import SlotWithFallback from "./SlotWithFallback.svelte";
</script>

<!-- will render h1 and p -->
<SlotWithFallback>
    <h1>Hello World</h1>
    <p>Some paragraf</p>
</SlotWithFallback>

<!-- will render <h2>There is no child content!</h2> -->
<SlotWithFallback />
```

### Named slots <a name="chapter-named-slots"></a>
Sometimes you will need to target different slots inside the same component. You can do this by adding names to slots:

####NamedBox.svelte
```html
<style>
	.box {
		width: 250px;
		border: 1px solid #aaa;
		padding: 1em;
		margin: 1em;
		display: inline-block;
	}
</style>

<div class="box">
	<slot name="top"></slot>
	<hr />
    <slot name="bottom"></slot>
</div>
```

####App.svelte
```html
<script>
    import NamedBox from "./NamedBox.svelte";
</script>

<!-- will render h1 in top slot and p in bottom slot -->
<NamedBox>
	<h1 slot="top">Title</h1>
	<p slot="bottom">Paragraph</p>
</NamedBox>
```

### Slot props <a name="chapter-slot-props"></a>
In Svelte 3 you can also reference variables of parent component. Let's create a box with a secret content that can be toggled using checkbox:

####Secret.svelte
```html
<script>
    let showSecret = false;
</script>

<label>
    <input type="checkbox" bind:checked={showSecret} />
    Show secret
</label>

<slot showSecret={showSecret}></slot>
```

####App.svelte
```html
<script>
    import Secret from "./Secret.svelte";
</script>

<Secret let:showSecret={isSecretShown}>
	{#if isSecretShown}
		<p>Hello world!</p>
	{:else}
		<p>***********</p>
	{/if}
</Secret>
```
In the example above we are referencing **showSecret** as **isSecretShown** (let:showSecret={isSecretShown}) and now we can use it as a variable. Personaly, I've found a bit stange the syntax, but I think you should understand it better this way: (expose)**let**:(property)**showSecret**={(as)**isSecretShown**}.