DEV Community

Tan Li Hau
Tan Li Hau

Posted on • Edited on

13 2

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

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (1)

Collapse
 
canrau profile image
Can Rau

Oh yes, this is incredible and exactly what I needed 🥳 thanks a lot 🙏

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more