DEV Community

Tan Li Hau
Tan Li Hau

Posted on • Updated on

2 ways to pass data into Svelte slots

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>
Enter fullscreen mode Exit fullscreen mode

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!

Watch on YouTube


When you use a slot, data in the slotted content can come from 2 components:

  1. the current component (A)
  2. the component we are using (B)
<!-- filename: A.svelte -->
<B>
  <div>i want {dynamic} {data}!</div>
</B>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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} />
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
  • 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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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} />
Enter fullscreen mode Exit fullscreen mode
<!-- 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>
Enter fullscreen mode Exit fullscreen mode

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} />
Enter fullscreen mode Exit fullscreen mode
<!-- filename: A.svelte -->
<B let:dataFromB let:updateData>
  <div>i want {dataFromB}!</div>
  <button on:click={() => {
    updateData(123);
  }}>Click Me</button>
</B>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

Reference

Top comments (1)

Collapse
 
canrau profile image
Can Rau

Oh yes, this is incredible and exactly what I needed πŸ₯³ thanks a lot πŸ™