Better boolean attribute behavior #409
Replies: 7 comments 1 reply
-
Hi! On being "silenced"Before I get into the meat of the proposed change, i have to strongly reject your framing of being "silenced" by us. You were explicitly told to start a discussion in this RFC repo, because significant changes to the framework require and RFC and are usually started with an informal discussion thread here before being formalized (you can read more on the process in this repo's README). Yes, we locked the issue the discussion started in, because that was a years-old issue in the Vue 2 repository which you seemed to have found and commented on years after the fact. And we closed the feature issue that you opened subsequently because you were asked to start an RFC discussion here. (By the way, and this is our fault for not properly noting this: vuejs/vue is the Vue 2 repository. Vue 3 lives in vuejs/vue-next at least for a few more weeks.) And yes, we made clear that we don't see the severity that you seem to feel about this and aren't very into this. That's not being "silenced", though - that's just our opinion / POV. Why an RFC Discussion?Because what you are asking is a big deal. You are asking us to revert a change that went through the RFC process with little objections, has been live in a stable release for more than 13 months. You are asking us to revert a change whose reversal would potentially break aria attributes in every Vue 3 app out there, and given how challenging it is to automatically test for some a11y stuff, this might even go into production in a lot of projects without being noticed. So if we accept this proposal, it will be for Vue 4, unless you can give some incredibly convincing argument about how the current is currently actively breaking Vue 3 apps all over the place - which so far, you didn't - and I don't think that's the argument you are trying to make anyway. Response to your proposalScopeSince you broadly speak of "boolean attributes", I'd like to preface my response with a bit of a definition of the scope, to the best of my understanding: Actual boolean attributes as per HTML spec (i.e. Your issue (and here I extrapolate from the previous conversation and not so much your points in this proposal) is with custom attributes that are semantically meant to be used as boolean attributes (i.e. because a custom element wants to treat them that way, or because a CSS selector wants to select for And concerning web components, the issue would only be an issue insofar as the custom element implementation doesn't provide a DOM property alongside the attribute - because Vue 3's default behavior is to set a DOM property if it exists, and fall back to an attribute only if that doesn't exist or you explicitly ask to set it as an attribute. SummaryThis problem that you see doesn't really impact Vue developers unless they work with a specific kind of custom element implementation, or a CSS framework relying on custom boolean attributes for selectors - both of which are rare in my personal experience at least. About confusion and odd behavior."Less intuitive"Yes and no. I agree that, especially if you are used to the Vue 2 behavior, this can be a little confusing at first, provided that you come across a situation where it actually comes to play. However, that also depends a bit on perspective. The current behavior is simply:
"More difficult"Yes. Undoubtedly, "More error-prone"
In the list of examples concerning
|
Beta Was this translation helpful? Give feedback.
-
Thanks for reading and for thank you for your thorough reply. I honestly thought this was going to closed and locked for a third time.
I wasn't, but I assumed "You can also propose a new discussion to change this behavior" meant open a Feature Request issue because that's where a lot of people make suggestions. Didn't know about Discussions. My bad.
Hey now, I joined the conversation after you reopened it. I first commented on an open ticket. Don't blame me. And yes, locking the conversations feature is definitely silencing. Doing that always comes across as rude and disrespectful. People take it as, "I think you need to shut up, so I'll make you shut up." No hard feelings, but come on there's no harm in letting people speak. Btw, comments on closed tickets are important - they can often lead to new information as the community catches up with the authors. Also, no one was breaking any community guidelines so no need to be draconian.
Well, of course Vue 3 projects aren't "actively breaking all over the place" because these breaking changes have to be fixed during the migration lol. That brings up another issue. It's really disheartening to see the Vue team tell me "you are the only person complaining" when the majority of the community hasn't even been exposed to Vue 3 yet: It's almost 10:1 and that's just one data point on where the community is. Another being all the Vuetify users (not me, but it's really popular) who have not been able to migrate to Vue 3 yet because Vuetify is incompatible. Hence my original comment to "revert [this] before v3 adoption hits critical mass". "Comparison with other Frameworks" CE As CE inevitably grow in popularity, Vue's behavior will be a sticking point for more and more devs. I also don't want to push too hard on an emerging pattern because it's mostly me afaik and this isn't even the primary driver behind the issue, but consider: <m-loader :loading="loading.messages">Getting your messages...</m-loader> That's not a CE. This component is custom HTML implemented with CSS. It may grow up to be a CE one day if JS is ever needed for its features, but today it only requires CSS: m-loader:before {
display: inline-block;
font-family: 'm-icons';
content: '\e627'; /* "sync" icon */
}
@keyframes m-loader-loading {
0% { transform: rotate(0deg) matrix(-1, 0, 0, 1, 0, 0) }
100% { transform: rotate(360deg) matrix(-1, 0, 0, 1, 0, 0) }
}
m-loader[loading]:before {
animation: m-loader-loading 1.2s linear infinite;
} Vue 3 broke all of my custom HTML that uses boolean attributes. Again, my issue is not a broken app - that's part of the deal when migrating to a major rev - it's the mental gymnastics as I now have to pause and think about attributes, then Also, making Vue more CE-friendly (by bringing back the Vue 2 behavior) is good for Vue adoption because apps like mine don't get stuck behind huge Vue-centric frameworks like Vuetify that are ironically incompatible with Vue 3 (no diss on Vuetify, but the age of framework-specific design systems is over). The deception of "true" and "false" strings In practice, "true" and "false" strings are really no different than "on" and "off", like in the case of By this same logic, Vue absolutely should be casting
Those six attributes define a "undefined" string in addition to "true" and "false", so it stands to reason then that "undefined" is no more of a "weird edge case" as you claim than "true" and "false" are. I get the desire to encourage a11y by making ARIA easier (although it's negligible considering The code devs write Let's not forget a few things that put casting bools to strings in the right context for discussing (a narrow context imo):
<span aria-haspopup="true">I always have a popup</span>
<div role="timer" aria-atomic="true"></div>
<div hidden>
<button disabled>
<input type="checkbox" checked>
<input type="email" required>
<textarea>
and more...
Negates the use of
<div aria-hidden="true">
<button aria-disabled="true">
<input type="checkbox" aria-checked="true">
<input type="email" aria-required="true">
<textarea aria-multiline="true">
These are the same, so removing is acceptable
<select>
<select aria-disabled="false"> Okay, so what we're left with is a very narrow problem space where all 5 of these have to be true:
That's the scope of this design decision. Should Vue abandon the power of Bringing back
|
Beta Was this translation helpful? Give feedback.
-
In Lit, Given that Vue already provides:
I propose adding a Long form (naming can be discussed): <foo :bar.bool="condition"/> Short form: <foo ?bar="condition"/> Rendered content if <foo bar/> Rendered content if <foo/> A note for CE authors: after Postel's Law, I'd advise that those predicates should be true (considering that
My impression is that some frameworks, like Stencil, enforces that. |
Beta Was this translation helpful? Give feedback.
-
I hate to encourage adding more things to learn, more ways of doing the same thing, more bytes to the Vue runtime, and I'm not a fan of proprietary template syntax like <div ?attr="falsy"> => <div>
<div ?attr="truthy"> => <div attr> I like it. From the framework's perspective This is also a non-breaking opt-in feature for Vue 3. For the 80% who haven't migrated to Vue 3 yet, adding Ship it! |
Beta Was this translation helpful? Give feedback.
-
@LinusBorg @posva thoughts on matching Lit's |
Beta Was this translation helpful? Give feedback.
-
Short answer, we will not revert the behavior because of the scale of impact as outlined by @LinusBorg. I think Linus has made the case very clear that it's not possible to revert the behavior without another major version, which we will not consider in the short term. This decision is final and the team will no longer respond to further requests on reverting the behavior. On the other hand, the |
Beta Was this translation helpful? Give feedback.
-
I'll submit a formal RFC tomorrow for |
Beta Was this translation helpful? Give feedback.
-
Ok, I'm trying this again. Apparently opening a "Feature Request" through Vue's Issue Helper is not where I'm supposed to go for feature requests. I was promptly sent here by @posva who is clearly annoyed by this topic. I'm sorry, I don't mean to irritate, but you never said to open an RFC, you told me to go read the old ones.
There's a genuine need for discussion here and from my pov it's being overly simplified, dismissed, and then silenced by the Vue team. For example, "you are the only person complaining about the improvement of writing :aria-value="boleanValue" instead of :aria-value="booleanValue.toString()"" is a very narrow view of the problem space and is resulting in hasty decision-making that doesn't address the nuanced needs of developers.
Below was copied and re-markdown'ed from vuejs/vue#12342 because I was locked out.
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 boolean values, i.e. it Just Worked. Attributes that need strings "true" and "false" were easily provided withbool.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 inattr="false"
, so you might expect Vue to givenull
equal treatment, e.g.setAttribute('attr', null)
results inattr="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 ensurenull
and notfalse
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
benull
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:
aria-required
need a string value of "true" or "false", however...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.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.aria-haspopup
, which supports 7 different string values, including "true" and "false".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
becomesnull
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?
Beta Was this translation helpful? Give feedback.
All reactions