-
-
Notifications
You must be signed in to change notification settings - Fork 33.8k
Description
What problem does this feature solve?
I understand there is already bias against this topic, but I'd ask for a chance to revisit it in more detail.
After the necessary removal of proprietary enumerated attributes behavior, the boolean attributes behavior has been made less intuitive, more difficult, and error-prone.
Less intuitive because HTML attributes take string values, so it was widely understood a boolean value of false
would result in no attribute at all, e.g. <div :attr="false">
would result in <div>
. This was ideal because the code for controlling these attributes naturally produced a boolean value, i.e. it Just Worked. Attributes that need strings "true"
and "false"
were easily provided with bool.toString()
, which made sense because HTML attributes only take strings. More on these attributes below.
Also, Vue now matches native setAttribute('attr', false)
which results in attr="false"
, so you might expect Vue to give null
equal treatment, e.g. setAttribute('attr', null)
results in attr="null"
, but it doesn't.
More difficult because developers now have to work against JavaScript to ensure their data, template expressions, methods, and/or computed properties result in an unnatural null
value. It may seem as simple as :attr="bool || null"
but any computed or method with logic branches the dev now has to go the extra mile to ensure null
and not false
is going to be the final output of the branching. Also, this logic :attr="bool || null"
just makes my brain go Huh? If false give me a null? Never written an expression like that before, would hate to have to scatter that all over my templates.
More error-prone because the odds of a value being a boolean are very high and the ubiquitous boolean is now a liability in templates. One way to mitigate this new risk is to make all things that could be false
be null
instead. This avoids the possibility of another dev using something that isn't boolean attribute safe. A terrible pattern, but if it means reducing risk devs may go that route. Gross.
Okay, on to attributes that take "true"
and "false"
strings...
It seems like what's happened is Vue has replaced some old special behavior (i.e. enumerated attributes) for new special behavior based on assumptions about the importance of a relatively small number of attributes that only take the strings "true"
or "false"
. In short, "true"
or "false"
was like a decoy that resulted in introducing odd behavior.
Let me explain with some examples:
- Sure, attributes like
aria-required
need a string value of"true"
or"false"
, however... - Attributes like
contenteditable
are likely given string values by the developer because"true"
and"false"
are just two of several possible strings the developer can set on that attribute. Devs can write code like:contenteditable="plainText ? 'plaintext-only' : 'false'"
, so it's strange for Vue to go out of its way to cast booleans to strings for the developer to support this case. - Same story with
aria-invalid
. It supports the strings"grammar"
,"spelling"
,"true"
, or"false"
. The developer will supply one of the four strings, not one of two strings or a boolean. Yes, someone could write the latter, but you see where I'm going. - Same again for
aria-haspopup
, which supports 7 different string values, including true and false. - And then there's
aria-expanded
andaria-pressed
, which support"true"
,"false"
, and"undefined"
(pressed also supports a fourth string"mixed"
). But if I give Vueundefined
it doesn't cast it to a string like it does forfalse
it removes that attribute, which made sense in Vue 2 but not now. Vue requires the developer to supply the string"undefined"
, but castsfalse
for them. Vue does this because it mistakenly believes there's something special about attributes that take"true"
or"false"
strings. This is not great and it's made even more weird becausesetAttribute('attr', undefined)
normally results inattr="undefined"
.
I think true and false string values can be awkward to reason about at first, so I can emphasize, but developers are now put in an even more awkward situation trying to ensure false
becomes null
as well as navigating what Vue will and won't do for them in regards to casting strings for attributes.
The fix
Developers are required to provide whatever string their attributes need, including the not special "true"
and "false"
strings, while Vue reserves the power of false
(and null
or undefined
) to remove attributes.
What does the proposed API look like?
These three values remove the attribute (uses removeAttribute('attr'))
<div :attr="false"> => <div>
<div :attr="null"> => <div>
<div :attr="undefined"> => <div>
True adds an attribute with no value, i.e. a boolean attribute (using setAttribute('attr', '') not setAttribute('attr', true))
<div :attr="true"> => <div attr>
Everything else (same as setAttribute('attr', val))
<div :attr="'true'"> => <div attr="true">
<div :attr="'false'"> => <div attr="false">
<div :attr="'null'"> => <div attr="null">
<div :attr="'undefined'"> => <div attr="undefined">
<div :attr="0"> => <div attr="0">
<div :attr="''"> => <div attr="''">
<div :attr="'hi'"> => <div attr="'hi'">