We've learned how to use slot in @sveltejs , now let's see how we can pass dynamic data to the slotted contents
<Component>
<div>i want {dynamic} {data}!</div>
</Component>
This article is a summary from my video from the "Svelte 101" series, "Passing data across slot"
If you prefer video, check it out for a detailed walkthrough!
When you use a slot, data in the slotted content can come from 2 components:
- the current component (A)
- the component we are using (B)
<!-- filename: A.svelte -->
<B>
<div>i want {dynamic} {data}!</div>
</B>
1. Passing data from the current component
Passing data from the current component (A) is what we've always do:
- define the variable in the script tag
- use it
<!-- filename: A.svelte -->
<script>
let dataFromA = 'dynamic';
</script>
<B>
<div>i want {dataFromA} {data}!</div>
</B>
2. Passing data from the component you are using
Passing data from the component (B) however, require us to pass the data as props to the slot
<!-- filename: B.svelte -->
<script>
let dataFromB = 'data';
</script>
<slot dataFromB={dataFromB} />
<!-- or using shorthand: -->
<slot {dataFromB} />
And to receives it, you create what we called a let:
binding
<!-- filename: A.svelte -->
<script>
let dataFromA = 'dynamic';
</script>
<B let:dataFromB>
<div>i want {dataFromA} {dataFromB}!</div>
</B>
- You starts with
let:
+ props name passed to the slot - The props name variable will then be available to your slotted content
- The let binding creates a new scope to the elements beneath to access the props variable
You can rename the props name as you need
<!-- filename: A.svelte -->
<script>
let dataFromA = 'dynamic';
</script>
<B let:dataFromB={somethingElse}>
<div>i want {dataFromA} {somethingElse}!</div>
</B>
This is especially useful when the prop name shadows the variable from the outer scope, and you want to access both the variables:
<!-- filename: A.svelte -->
<script>
let data = 'from a';
</script>
<B let:data={dataFromB}>
<div>data from A: {data}</div>
<div>data from B: {dataFromB}</div>
</B>
Slot props for named slots
Remember named slots?
You can choose to pass different data for different slotted content!
<!-- filename: B.svelte -->
<script>
let title = "Passing data to slot";
let content = "Svelte is fun!";
</script>
<slot name="header" {title} />
<slot name="body" {content} />
<!-- filename: A.svelte -->
<B>
<svelte:fragment slot="header" let:title>
<h1>{title}</h1>
</svelte:fragment>
<svelte:fragment slot="body" let:content>
<div>{content}</div>
</svelte:fragment>
</B>
Reactive data
Well, the let:
binding is not 2-way, (not for now ๐)
To pass data back to the component B, you'll need a callback function
<!-- filename: B.svelte -->
<script>
let dataFromB = 'data';
function updateData(newData) {
dataFromB = newData;
}
</script>
<slot {dataFromB} {updateData} />
<!-- filename: A.svelte -->
<B let:dataFromB let:updateData>
<div>i want {dataFromB}!</div>
<button on:click={() => {
updateData(123);
}}>Click Me</button>
</B>
Well, an alternative to callback function would be using a store, however using $
for a store that is not declared at the top-level of the script is not supported yet!
...and the workaround doesn't seem better to me ๐
<!-- filename: A.svelte -->
<B let:dataFromB>
<!-- โ ๏ธ Stores must be declared at the top level of the component (this may change in a future version of Svelte) -->
<div>i want {$dataFromB}!</div>
<button on:click={() => { $dataFromB = 123; }}>
Click Me
</button>
</B>
<!-- Workaround -->
<script>
import { get } from 'svelte/store';
</script>
<B let:dataFromB>
<div>i want {get(dataFromB)}!</div>
<button on:click={() => { dataFromB.set(123); }}>
Click Me
</button>
</B>
Reference
- Svelte tutorial: Slot props https://svelte.dev/tutorial/slot-props
Top comments (1)
Oh yes, this is incredible and exactly what I needed ๐ฅณ thanks a lot ๐