sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
77.79k stars 4.06k forks source link

Input resets when page fully loads #8266

Closed nkitsaini closed 4 months ago

nkitsaini commented 1 year ago

Describe the bug

If you load a page which contains an input element with value binded to a variable, the input will reset all the user edits when page load finishes.

# Timeline
- Page starts loading
- `input` becomes visible on screen
- user edits the `input` to some value
- Page finishes loading. Edits are gone.

I'm not sure if this falls exactly into svelte-kit and will this be considered a bug or not. But it sure is little annoying sometimes.

Reproduction

Repo: https://github.com/nkitsaini/svelte-bug-repro Video: https://github.com/nkitsaini/svelte-bug-repro/raw/main/repro.mkv Snippet:

<script lang="ts">
    let a = "234"
</script>

<input bind:value={a}>

Logs

-- No Logs --

System Info

System:
    OS: Linux 6.1 Arch Linux
    CPU: (16) x64 AMD Ryzen 7 5825U with Radeon Graphics
    Memory: 30.83 GB / 38.02 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 19.6.0 - /usr/bin/node
    npm: 8.19.2 - /usr/bin/npm
  Browsers:
    Chromium: 109.0.5414.119
    Firefox: 109.0.1
  npmPackages:
    @sveltejs/adapter-auto: ^1.0.0 => 1.0.2
    @sveltejs/kit: ^1.0.0 => 1.3.10
    svelte: ^3.54.0 => 3.55.1
    vite: ^4.0.0 => 4.1.1

Severity

annoyance

Additional Information

No response

dummdidumm commented 1 year ago

This sounds like a timing issue - hydration happens too late, so it clears out the value the user has already typed in. This is not strictly related to SvelteKit, more a general limitation of the current Svelte hydration.

Rich-Harris commented 1 year ago

A decent workaround is to disable the input until hydration has completed:

<script lang="ts">
+   import { browser } from '$app/environment';
    let a = "234"
</script>

-<input bind:value={a}>
+<input disabled={!browser} bind:value={a}>

Ultimately it would be better if the binding was initialized with the input value — not sure if that would cause other problems, but I'd like it if we could do that in a future version of Svelte.

nkitsaini commented 1 year ago

Yeah, the suggested workaround is good enough for my use-case. It is interesting that browser is false until hydration.

Rich-Harris commented 1 year ago

Transferring to sveltejs/svelte since there's nothing we can do here

adiguba commented 1 year ago

Svelte could perhaps check the value of the binding just after hydration ?

Something like this approximately :

    input = claim_element(nodes, "INPUT", {});

    // When input is different from the context value
    if (input.value !== /*a*/ ctx[0]) {
        // We use the binding handler to update it's value
        /*input_input_handler*/ ctx[1].call(input).
    }
rmunn commented 1 year ago

Probably a duplicate of #1755, which tells you how long this problem has been around.

Gerschtli commented 11 months ago

@Rich-Harris Ultimately it would be better if the binding was initialized with the input value — not sure if that would cause other problems, but I'd like it if we could do that in a future version of Svelte.

Did you have a look into this idea already? I think it would be a good thing to implement because this issue is indeed quite annoying and disabling the input until JS loads also seems like a unnecessary delay.

Would be great to have at least the option to enable that via svelte without some hacky workarounds. What do you think? Would love to support you there on that topic, despite svelte code base being new for me :)

enyo commented 8 months ago

A decent workaround is to disable the input until hydration has completed

@Rich-Harris Now that we have nice forms that work without JavaScript via use:enhance it's a pity that this is the solution, since it renders SSR forms kinda useless. Hopefully this is something that can be resolved in the future by hydrating with the correct values.

Rich-Harris commented 4 months ago

closing as dupe of #1755