Open ITenthusiasm opened 1 year ago
Update: It might actually be difficult for Svelte to implement this change simply by letting attributes like value
behave as normal. This is because almost certainly, there are several applications out there using bind:value
-- unaware that the code that's being written actually diverges from what normal HTML would do/expect.
Svelte could do it, but it would be a significant breaking change, and it would leave people without the ability to use bind:value
. (Though, in my opinion, bind:value
could easily be replaced with pure JS.) Perhaps a better alternative would be for Svelte to identify all of the areas in which it deviates from pure HTML. Then, in those moments of deviation, it could perhaps introduce something like a native:*
directive? That way, the developer can express that they just want the pure attribute there; they don't want any JS magic. For instance, a developer could use native:value="default-value"
or native:checked
or native:selected
.
I think Svelte should be able to support the native default value use case for textarea
s without causing a problematic breaking change. Developers would still need to use bind:value
if they wanted data binding for that element anyway.
Note: Somehow Vue seems to have found a way to support both the JS magic and the native default value use cases individually? I don't really know how they've done it. Either it's intentional, or there's a bug somewhere. But if it's intentional and there's a desire to avoid introducing new syntax like native:*
, then maybe Vue's approach would be worth exploring?
What we can do is special-case the "value was set statically" and in this case don't clear the value. What we cannot do is do that when the value is set through a variable. In that case we don't know whether or not the initial value should be the one that's the default value - and in fact, both Solid and Vue behave that way. Maybe it's intentional, maybe it's by accident, but both don't set the initial value as the default value when you pass a dynamic variable to for example value
in <input>
.
Update: In fact, this is how it works already now in Svelte 5. We just need a test to ensure we don't accidentally regress there.
In that case we don't know whether or not the initial value should be the one that's the default value - and in fact, both Solid and Vue behave that way.
Ah, I was wondering what was causing that discrepancy in Vue. That's helpful! Thanks for identifying that!
In fact, this is how it works already now in Svelte 5. We just need a test to ensure we don't accidentally regress there.
That's encouraging to hear. I'm looking forward to Svelte 5's release then. 🙏🏾
What we cannot do is do that when the value is set through a variable.
That is an interesting dilemma. In most cases, I don't think that this is a big deal. Being able to use default values at all is a huge win. But there might be some edge case concerns. Is this limitation on the client side only or also during SSR?
(Also, thanks for taking the time to consider/review this issue.)
Linking some findings from a related PR: #10617
Investigated this more. Here are my findings:
<input bind:value/checked>
and <textarea bind:value>
this is straightforward: support setting the defaultValue
property (or defaultChecked
in case of a checkbox/radio)<input bind:group>
it seems very hard to get a default value into all the logic that exists. Theoretically it should be doable though; you'd set checked
on one of the elements. For static checked it works nicely because the value is inlined into the template and so the form reset can do its magic.<select>
it becomes hairy. We have two options:
defaultValue
for the <select>
element, similar to what react has done. This requires an extra reset
event listener with purpose-built logic for the select, even if you're not using <select bind:value>
.selected
on the appropriate option entries. This works nicely when the value is static, because then it's inlined in our template string (in fact it already works today then), but it doesn't work if it's dynamic, because then it's only set as a property - but we have to set it as an attribute so that the native browser reset can do its magic. This also a purpose-built set_selected_attribute
because since #13327 our set_attribute
does set the attribute as a property if there's a setter and the value is not a stringThere are also questions around what to do if defaultValue
and value
is falsy - should the default value take precedence in that case, or not? And should it differ between whether or not you bind:
to the value?
Describe the problem
Unfortunately, as of today, Svelte does not support default values[^1] for form controls. For example, Svelte renders
as
as
and
as
(It's also a little odd that the
value
attribute is added here when it wasn't specified in the HTML. But for now, I'm only interested in the missingselected
attribute.)This dissonance between
Svelte
andHTML
results in an unintuitive experience for developers intending to use Svelte as a superset of HTML, and it acts a roadblock to important features in forms. One example is that this behavior prevents form resets from behaving correctly, as pointed out in #8220. Another example is that it prevents developers from using thedefaultValue
/defaultChecked
/defaultSelected
attributes of fields to identify "dirty controls" -- a common use case in forms.When using native HTML/CSS/JS, these
default*
properties can be used to check which fields are dirty. The same code works just fine in Solid.js and Vue. (It's worth noting that neither Vue nor Solid add thevalue
attribute to theoption
s if it wasn't specified.) Amazingly, React almost completely supports this use case as well. Onlyselect
elements don't work because they don't support theselected
attribute currently. So I was a little surprised to see that Svelte doesn't support this use case at all -- not even forinput
s. (If you see things turn red in Svelte's demo, it's because JS is comparing field values with non-existing default values the entire time, not with anything that's an actual default value. So everything stays red -- except the checkbox, for obvious reasons.)It would be fantastic if Svelte could support default values. I would even be bold enough to say that this is a necessary feature (since not having the feature is technically a regression from browser behavior).
[^1]: It seems that svelte uses JS to simulate giving a form control a default value. However, this is not a "true" default value. It's more like an onMount side effect that still leaves the developer without the browser's features surrounding default values. Hope that isn't too confusing.
Describe the proposed solution
During SSR and CSR, Svelte should render all form controls with the exact markup that they're given. That way, default values will be supported out of the box, and no attributes will unexpectedly disappear from (or force themselves upon) form controls.
Alternatives considered
Using state is a possible way around this problem, but it's more complicated and likely less performant for obvious reasons. Besides that, I don't think there's an alternative solution to preserving the developer's intended markup for form fields.
Importance
I cannot use Svelte without it