Open ITenthusiasm opened 11 months 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.)
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