svelte icon indicating copy to clipboard operation
svelte copied to clipboard

Hydration clobbers input into form

Open ispyinternet opened this issue 5 years ago • 15 comments

If your form has just been server rendered and you initial bind the values to empty string, when a user starts to enter data into the form it will get clobbered by hydration.

You can disable the inputs until the page hydrates, but I like my site(s) to be snappy and don't want to block the form out until hydration, admittedly its not an eternity, but its enough for me to drag it to the table.

RH has indicated that if this were standard behaviour some use cases would present weird / unsuitable UX experience, for example typing into a search input doesn't result in the autocomplete dropdown appearing.

In which case I would like to request some optin behaviour to prevent hydration from clobbering the form inputs.

<input bind:value:nohydrate=username>

or something of that ilk?

ispyinternet avatar Sep 25 '18 15:09 ispyinternet

To be fair, this is caused by an excessively large file, but where is that cutoff and what will be the demands of user apps?

ispyinternet avatar Sep 28 '18 13:09 ispyinternet

Closing as a duplicate of https://github.com/sveltejs/svelte/issues/4308. This issue isn't specific to form input, but multiple elements that are negatively affected by being destroyed and recreated such as videos and animations

benmccann avatar Jun 14 '21 03:06 benmccann

I feel that it might make sense to keep this as an separate open issue. I don't believe the cause is only destroying/recreating nodes but also calling set_input_value when mounting the elements. So even if we never destroy & recreate, form inputs will likely reset.

hbirler avatar Jun 15 '21 19:06 hbirler

Ticket #4308 is solved but the problem persists, where hydration removes the input that has been done up to this point.

andreasnuesslein avatar Jun 13 '22 12:06 andreasnuesslein

You can disable the inputs until the page hydrates,

@ispyinternet do you have a nice way of doing this? Or just some boolean variable that gets changed on "onMount"?

andreasnuesslein avatar Jun 13 '22 12:06 andreasnuesslein

@benmccann pinging you directly as you were the one closing this ticket. I still the problem described in this ticket still exists. Could you revive this ticket? :)

Cheers

andreasnuesslein avatar Jun 20 '22 21:06 andreasnuesslein

@andreasnuesslein could you provide a minimal reproduction? Assuming the original case was addressed we will not have a way to reproduce otherwise

benmccann avatar Jun 21 '22 00:06 benmccann

@andreasnuesslein could you provide a minimal reproduction? Assuming the original case was addressed we will not have a way to reproduce otherwise

I still mean to create an example. I've only been out of business with the flu for the last 10 days :\ Slowly gettin' better.

andreasnuesslein avatar Jun 29 '22 13:06 andreasnuesslein

I finally made an example @benmccann

https://github.com/andreasnuesslein/svelte-ssr-issue

Basically I created a new sveltekit project (npm init svelte svelte-ssr-reset-example) and modified the index.svelte and created the sleep.svelte. No other changes. The README.md contains the steps to reproduce.

andreasnuesslein avatar Aug 01 '22 09:08 andreasnuesslein

Second this, prepared a nearly identical repro: https://github.com/thoughtspile/svelte-hydration-repro

thoughtspile avatar Aug 08 '22 15:08 thoughtspile

Reproduced for me with latest svelte. Also it resets focus on input element too during hydration.

istarkov avatar Sep 27 '22 13:09 istarkov

One way or another @benmccann , I understand it's not on the top of the list at the moment, but could you please re-open this issue? It's just not solved yet.

Cheers

andreasnuesslein avatar Nov 08 '22 13:11 andreasnuesslein

This has been very frustrating experience for me as well, and should certainly be reopened. However, I'd like to share a workaround in the meantime.

During initialization, it is possible to set the bound variable to the browsers current element's value. Like so:

<script>
  let value
  if (document) {
   value = document.querySelector('input[name="x"]').value
  }
</script>

<input name="x" bind:value />

N.B.: I'm using this with bind:group in a sveltekit app and guard it with browser from $app/environment

janvogt avatar Feb 21 '23 20:02 janvogt

In https://github.com/sveltejs/svelte/issues/8266#issuecomment-1456411585 there was a suggestion for claiming <input> nodes during hydration that seems good to me; copying it here so that it won't get lost if #8266 is closed as a duplicate.

	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 avatar Jul 10 '23 03:07 rmunn

We run this userland workaround in production, seems to do the trick with the caveat of not triggeing on:input:

<script context="module">
	const preHydrationValues = new WeakMap();
	// client-side only
	typeof document !== 'undefined' &&
		document.querySelectorAll('input').forEach((input) => {
			// only for changed inputs
			if (input.value !== input.getAttribute('value')) {
				preHydrationValues.set(input, input.value);
			}
		});
</script>

<script>
	export let value;
	function restorePreHydrationValue(node) {
		const savedValue = preHydrationValues.get(node);
		if (savedValue) {
			node.value = savedValue;
			value = savedValue;
			preHydrationValues.delete(node);
		}
	};
</script>

<input
	use:restorePreHydrationValue
	bind:value
	{...$$restProps}
/>

thoughtspile avatar Jul 12 '23 19:07 thoughtspile

I also found this bug very frustrating and hard to diagnose. Seems like a huge gotcha that needs to be pointed out in the docs when using universal loading. My solution has to just been to not use universal loading at all and instead use server loading, but I am curious to know what other people building Sveltekit apps are doing and if this is viewed as a bug that plans to get fixed or what the recommended way of dealing with this is.

pjb3 avatar Nov 05 '23 12:11 pjb3

I think this will probably be addressed by Svelte 5, but am not positive. We should test when it's available

benmccann avatar Nov 05 '23 13:11 benmccann

I think this will probably be addressed by Svelte 5, but am not positive. We should test when it's available

@benmccann That would be great, I'll test it out when it comes out

pjb3 avatar Nov 05 '23 14:11 pjb3

yes, it's a supper annoying issue, basically if user touch input before hydration is finished - it should be avoided by hydration. It still race condition possible but it should significantly mitigate it.

stalkerg avatar Apr 17 '24 05:04 stalkerg