Async derived causes bind:this refs to revert to initial state when passed as props
Closed this issue ยท 17 comments
Describe the bug
The Popover from bits-ui is not opening under certain weird conditions.
Broken since 5.43.0
Edit: I have narrowed down the issue and made a REPL that has no bits-ui dependency to expose the svelte reactivity bug.
Reproduction
Logs
System Info
svelte playgroundSeverity
blocking an upgrade
--bits-floating-transform-origin: undefined undefined;
--bits-floating-available-width: undefinedpx;
--bits-floating-available-height: undefinedpx;
--bits-floating-anchor-width: undefinedpx;
--bits-floating-anchor-height: undefinedpx;I guess bits-ui miscalculates something or uses outdated references.
It works when you navigate back to the page though, but not after refreshing the page which makes me think it's a svelte bug but idk
The popover's logic is spread across dozens of files + floating-ui repo. It's too complex for us to unwrap the logic.
Open an issue in bits-ui. If it's Svelte's bug, the authors will come here with a simpler reproduction.
I fixed it by adding this dependency to the $effect but my feeling is that there is a deeper svelte bug here related to the effect dependency chain. Sorry I don't know how to make a minimal repro :(
Locally, in my private project, this has been fixed.
When I change the repl to: https://svelte.dev/playground/3029fe42f2fb4100bab1635964a4749f?version=5.43.4 , it seems to work again. Can someone confirm that svelte runs in async then?
In the original REPL, i don't really understand this line:
let foo = $derived(await open);
If you await open, it breaks. I'm not sure why open is being awaited either. If you await anything else, it works. However, awaiting open did work in 5.42.0 and breaks in 5.43.0.
@vyconm One thing to note though, is that your example (awaiting a promise) works in 5.43.0 - 5.43.3 as well.
@sillvva could be that the playground is not detecting aync svelte?
another point might be the use of bind: to control the open state. There are other issues related to bind: and aync svelte here. My Private repo is always using the built-in trigger.
see this modified repl bugging out now that we use open to control state:
https://svelte.dev/playground/3029fe42f2fb4100bab1635964a4749f?version=5.43.4
async is enabled in the playground. And yeah, there are some issues with bind: in general at the moment.
I tried checking your latest REPL. EDIT deleted my own irrelevant comments. The popover component doesn't work without a trigger, whether you're using the trigger to toggle it or not. 5.43.0 REPL
await open resolves within the same macrotask, while await stall() (delaying via a timer) is resolved in another macrotask.
Likely some race happens.
But this REPL has a lot of logic under the hood, so it's tricky to find the problem.
This is still broken in the latest svelte version. Here's another interesting reproduction.
This time I don't bind the open state at all.
<script>
import { Popover } from "bits-ui";
let value = $state();
let foo = $derived(await value);
</script>
<input bind:value />
<Popover.Root>
<Popover.Trigger>Open Popover</Popover.Trigger>
<Popover.Content>
<p>Popover Content</p>
</Popover.Content>
</Popover.Root>
{#if value}
<p>lol</p>
{/if}