From the documentation of slots it seems it should be possible to bind values of a component to a slot:
Slots can be rendered zero or more times, and can pass values back to the parent using props. The parent exposes the values to the slot template using the
let:directive.
but it seems that the real situation is different: this REPL triggers the error Cannot bind to a variable declared with the let: directive (10:32).
Expected behavior
Binding a variable in a slot, which is bound to a variable in the parent component, should work normally as it would if I manually substituted the slot content inside the container.
Severity
This underpins the possibility of developing a lot of components that take care of boilerplate code for my application, so in my case this effectively blocks my usage of Svelte for the project.
Hi,
The part of the documentation you mention doesn't say what you interpreted. Binding values is different from exposing a property from the slot to the parent. It will be helpful to said what are slot are and use for.
Slots are just placeholder:
The HTML
element—part of the Web Components technology suite—is a placeholder inside a web component that you can fill with your own markup, which lets you create separate DOM trees and present them together.
The slot tag will be "replace" with the html markup that you put inside your Component tags. A use case can be...
Let's said you want to create a DataTable component, on the DataTable component you create all your table html markup, style and javascript. So to use the component i just need to pass a dataset, where this dataset is an array of objects.
How you display each one of those items and in which order? You don't know, because when you created the component you din't have the data and you what to use this component for different type of objects.
So instead of creating complex configuration for the component you just expose each object (item) of the dataset to the parent. So here you will use a slot, so future developers and you can said how the markup of a row will be, and with the expose item you have the data of your dataset that you pass to your component available.
So svelte documentation saids:
Slots can be rendered zero or more times, and can pass values back to the parent using props. The parent exposes the values to the slot template using the let: directive.
Continuing the documentation after the previous line it saids:
The usual shorthand rules apply —
let:itemis equivalent tolet:item={item}, and<slot {item}>is equivalent to<slot item={item}>.
This means that to expose a property from the slot child to the parent you need to do:
<slot {item} /> or <slot item={item}></slot>
And to use that property on the parent you need to do:
let:item or let:item={item}
Check the svelte example on this part of the documentation for better understading. If you don't do that, the item on the parent will be undefined. Thus not having access to the data you which.
On the other hand... Binding
In a nutshell, the purpose of this is to update the variable programmatically or when the DOM element/components updates it. So if you have an input that his value is bind to a variable X when the input change it will change the value of the variable X but also if you change the value of X programmatically it will also change on the input and any place you reference the variable X.
From svelte tutorials we can bind to components properties too:
Just as you can bind to properties of DOM elements, you can bind to component props.
But to components props, and to create a prop you need to use the export keyword. More on component bidings.
The extended explanation is in case you miss something and for future devs that find this issue, have a better understanding of slot and binding, and more if they're beginners to Svelte.
From your REPL I edit it a little, maybe this was what you were trying to do.. It binds to the components and also expose the value to which it binds. Making it posible to update the given value from inside the component but also from outside the component while also exposing the value from the slot to the parent.
Or, are you asking for the functionality that one can specified future bidings to the slot?
Thank you very much for the explanation: I though I knew slots but I didn't.
Now that I got a clearer picture, I still don't understand why that error message (cannot bind to variable declared with let:) is there, in the sense that for me it would make a lot of sense to both bind (which connects bidirectionally the App#item variable with the Component#item variable) and also let (which connects the slot#item variable with the Component#item variable, allowing data to flow from slot to Component, and thus to the top-level App via the bind syntax.
I have seen your example and it works, but I think that this , having multiple objects that I would like my internal template to bind to.
I think this problem cannot be solved, as of now, in svelte.
I definitely think that I'm asking for future bindings to the slot, if that means to bidirectionally bind the slot#item variable to the Component#item variable.
I also add an image to better explain my understanding of the current situation:

Hi,
I came across a similar/relevant issue where I'm wanting to use slot props to pass a value to a parent component so that it can be bound to a specific element in the slot. This would allow the component containing the slot to access the DOM element in onMount.
For example,
<Field let:input={input}>
<label>X</label>
<input bind:this={input}/> <!-- Cannot bind to a variable declared with the let: directive -->
</Field>
Here's a REPL that illustrates the same issue: https://svelte.dev/repl/94dfa039dfd645ad8265609377873457?version=3.20.1
My intention is for the Field component to be able to access the input DOM element in onMount.
I've tried passing a variable input into Field as a prop and also binding it to the input, however when onMount is called in Field, it appears that the reference to the input element is null.
Is it possible for Svelte to support this type of binding?
I would love to see this features as well, since it makes component composition and reuse a lot easier.
I also wanted to use this in a way to provide a context for child components, where the parent component contains a bunch of boilerplate that the child components shouldn't have to worry about, and the parent provides two-way bindable variables that children can take as props.
Slots seem like these magical things that easily break when you play around with them too aggressively, I guess the benefits of a compiler don't matter when Svelte treats slots as though _literally anything_ might fill them.
I happened upon this issue while investigating a slightly different usage. May I ask why it isn't possible to do the following. Am I misunderstanding the question? I get that the let:item directive is a nice shorthand, yet isn't this still possible?
<!-- App.svelte -->
<script>
import Component from './Component.svelte';
let item = 'hello, world';
</script>
<Component {item}>
<p>
Inside the item is {JSON.stringify(item)}
</p>
<input type="text" name="name" bind:value={item} />
</Component>
<!-- Component.svelte -->
<script>
export let item;
</script>
<p>
Outside the item is {JSON.stringify(item)}
</p>
<slot />
@kjmph Seems to be working in the REPL: https://svelte.dev/repl/72d0ab2799a04343bc8054176ee4208d?version=3.25.0
Thanks for placing it in the REPL. It seems that the let:item directive doesn't work, yet using it verbosely works? Unless I misunderstand the issue.
@kjmph Well that won't work since you can't redeclare item, but you can do this: https://svelte.dev/repl/0133298870654061a2fb8ed5b8a8f65e?version=3.25.0
Ahah, I think you showed the problem. If we change Component.svelte to:
<script>
export let item;
</script>
<p>
Outside the item is {JSON.stringify(item)}
</p>
<slot foo={item+"nana"} />
Then the output is:

Instead, if we really want two way mutation between parent and child, then it is best to represent it like this:
<!-- App.svelte -->
<script>
import {item} from './stores.js';
import Component from "./Component.svelte";
$item = 'hello, worl';
</script>
<Component>
<p>
Inside the item is {JSON.stringify($item)}
</p>
<input type="text" name="name" bind:value={$item} />
</Component>
```svelte
Outside the item is {JSON.stringify($item)}
```javascript
// stores.js
import {writable} from 'svelte/store';
export const item = writable('hello, world');
Just type the letter d in the input box, and watch the input value change.
This question subtly brought up a few points about Svelte I didn't understand. Which is why I have commented and looked into it at a greater depth. @trenta3, your link to show the problem results in a Non-Image content-type returned response; so it is hard to figure out what the issue is. I realize two things, using stores is a bit boilerplate. So, it seems people want to do things like this:
<!-- App.svelte -->
<script>
import Component from "./Component.svelte";
let items = ["foo", "bar", "mung"];
</script>
{#each items as item}
<Component bind:item>
<p>
Inside the item is {JSON.stringify(item)}
</p>
<input type="text" name="name" bind:value={item} />
</Component>
{/each}
<!-- Component.svelte -->
md5-ddce589b1661642059396a5abeb0257e
md5-6ed10d799daa45f34b136f36cc6bb113
<slot {item} />
md5-de10c8a673b097602602b3f01701efc6
```svelte
<!-- Component.svelte -->
md5-283338479215b505ee347ae12a43b29f
<slot {input} />
It all has to do with how binding works. It is very non-intuitive, yet makes sense once grokked.
@kjmph I can see my image correctly when visualizing it in GitHub: https://user-images.githubusercontent.com/10828817/71427308-93471000-26b7-11ea-84fd-b5b1a970fd5a.png
Concerning all the updates, I didn't have time to read them yet because of quite busy days.
I will come back to it though in a few days.
Ah, I was referencing the REPL link that was shared. If you would like to re-post that, maybe we could coerce a solution to your liking.
I think the point I've been circling, and why I got involved on the issue thread is that the let:item is confusing, and also not needed. I'm going to mess up an explanation since I don't know Svelte internals. However, it appears the problem is that the slot's bind doesn't have a direct reference to the variable stored in the component itself. If we disable the warning message in Svelte, and allow us to bind to the let:item we find that we don't receive updates from the component. I'm guessing this is because let:item is a copy, which explains why the let directive can accept a different variable name in the slot. Thus, even if input is bound to the let:item, it is bound to a local copy in the slot, which isn't re-copied until the slot is re-hydrated.
Thus, with that understanding, it should be hopefully clearer that the item needs to have a location/variable that the compiler can see in the App for the slot to bind to, so that the data flows reactively. Thus, the storage should be somewhere the compiler can see it, either through a writable via svelte/store or through variables in the App <script> section. This means that you can bind the item, and pass it direct to the Component, e.g. <Component bind:item>. Also, the slot can bind item directly, since the storage is in a known location.
Technically, in my example above, this means that when mounting the slot in the Component, e.g. <slot item={item} />, the slot props do not require the item being passed back to the slot, since the slot can reference it directly. It could be written as <slot />.
Now, I'm not a Svelte dev, so I'm sure I misused some of that terminology. Does this help?
Most helpful comment
Hi,
I came across a similar/relevant issue where I'm wanting to use slot props to pass a value to a parent component so that it can be bound to a specific element in the slot. This would allow the component containing the slot to access the DOM element in
onMount.For example,
Here's a REPL that illustrates the same issue: https://svelte.dev/repl/94dfa039dfd645ad8265609377873457?version=3.20.1
My intention is for the
Fieldcomponent to be able to access theinputDOM element inonMount.I've tried passing a variable
inputintoFieldas a prop and also binding it to theinput, however whenonMountis called inField, it appears that the reference to theinputelement is null.Is it possible for Svelte to support this type of binding?