Vue drops `value=""` from `<button>`
Vue version
3.2.37
Link to minimal reproduction
Steps to reproduce
Visit testcase
What is expected?
Both buttons should have a green outline (applied on button[value]
)
What is actually happening?
The button inside the Vue app does not have a value
attribute after Vue renders.
System Info
No response
Any additional comments?
This seems too basic to have gone undetected, so sorry if I'm missing something obvious!
vue doesn't add the value attribute to the element if its empty .(edited) ( see https://github.com/vuejs/core/issues/6277#issuecomment-1187714777 for more correct analysis)
<button id="a" value='' disabled=''></button>
renders to
<button id="a" disabled=''>
and so the css selector of button[value]
is falsy
There are however workarounds, for this less common use case.
for example
<button :value.attr="''" ></button>
which forced binding the attribute, and it can not be removed anymore based on value.
Yeah, :value.attr="``"
is what I ended up doing, but it seems strange to have to use Vue specific stuff to preserve markup in an element that never even had any Vue attributes or expressions in the first place. I knew that Vue removes attributes when the value is null
, but not when it is ""
. Furthermore, empty attributes do appear to be preserved in other cases, e.g. <img src="" alt="" />
, which seems inconsistent.
here is the reassessed relevant general logic vue follows.
1. if the attribute name exists as an element prop, set the element prop. 2. if the value is null, remove the attribute ( empty string should not remove attribute, with the exception of prop with a number type) 3. when the attribute name is value there is an additional logic. Only set the prop when the provided value is different than the existing prop value 4. setting an element prop may be expressed as an element attribute
in the case of the <button>
the default value of the value prop
is an empty ''
string
based on rule(3) and rule(4) the prop is not going to be set, and the attribute is not going to be shown
This is what creates the apparent inconsistency. for value
attribute and other known element attributes.
thankfully forcing setting as explicit attribute exists and can be used as the workaround.
it can be fixed on vue side, by explicitly setting value prop, for empty string, even if the value is the same.
I get this also with a hidden field:
<input :name="name" value="" type="hidden" />
name
and value
are props to the component that holds this template. Renders as just:
<input name="my_field" type="hidden">
Didn't use to do this under Vue 2. The :value.attr="''"
trick works. With that in place I correctly get this like I did for Vue 2:
<input name="my_field" value="" type="hidden">