-
-
Notifications
You must be signed in to change notification settings - Fork 942
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Boolean attributes #1101
Comments
I think potentially there's a 5th desired property:
Maybe this isn't super desirable or it's too much of an edge case, but since using Solid with React's transform is supported I'd find it strange if something completely static like |
To be clear, this wouldn't affect directives, correct? i.e. |
what about the case where you want to remove the attribute |
Correct. It won't even affect props in components:
I took a stab at implementing the proposal here: ryansolid/dom-expressions#141 |
Fixes solidjs/solid#1101 by making `<div foo={true}>` behave like `<div foo>` and `<div foo="">`
yes
but then isn't odd if true does this: ? |
I see. In general we set known boolean attributes by property and everything else by setAttribute. I see I left boolean(no arg) working like a boolean in it literally sets empty string but this is probably wrong. A boolean attribute cannot be removed so there is no inconsistency on that side but it means we probably should be setting it to true. We used to do this the other way but there are attributes that actually want "true" and "false". I think we should continue checking against the list and apply it to the boolean form. I guess thats siding with React. But the other way is no good either. There is no guarantee it ends up in the DOM through a component so it has to come in as EDIT: If you are wondering the source of Solid's implementation. As usual Inferno is what I trust for these sort of things. React probably has the most thorough but I suspect this is a place both Inferno and Preact save size by doing something reasonable. |
Some helpful resource (from React).
Nothing is mentioned about Edit: |
This is a great analysis of React behavior @lxsmnsyc! I think this line actually makes Obviously one option is to reproduce React's behavior. I think there's still an open question of what to do with attributes that aren't on any of these lists:
Personally I think Option 2 makes sense, given HTML spec, but it differs from both current Solid and React. An advantage of this approach is that you only need a list of "enumerated but Boolean-like" attributes, like those listed in bullets 1 and 2 of @lxsmnsyc's post and |
With |
Good point: |
If I didn't make it clear in my previous response. While I see potential of changing more things and doing stuff differently. It's the first row that is the bug today and should be fixed. We already default to true except for a pass-list and I'm not prepared to change that at the moment. We were the other way in the past but it caused other confusion and errors. So I've updated this case to use that pass-list: |
For what it's worth, I recently bumped into this React GitHub issue where users were confused about the inconsistent behavior, in particular for At the least I think we need to document things clearly here. (Personally I'd also much rather have the default be "like HTML" instead of "like React".) |
I think we should follow the convention of handling booleans for specific attributes, just for consistency. It's just a small price to pay. |
but this generalization works for any known and unknown boolean attribute ( will passing "true" to a known html attribute be considered non standard? will it not work as expected?) it is also more or less consistent between Component and an Element. Element
Component<MyComp foo/> const MyComp = function(p){
console.log(p.foo===true) // true
...
} null value
and if one doesn't like the "true" they can be explicit and set |
This thread is relevant here: #383. Where I justified the current behavior at the end by being browser. But I didn't realize the inconsistency with spread. It looks like I pulled inspiration from Svelte for the current behavior but did not test spread there I assume. I do think coercing That being said from my previous research not a single other JavaScript framework aligns with the browser here. true means "true" and false means "false" with exception of the pass-list. Even close to the browser frameworks like Preact or Svelte. Preact works identical to how I proposed to fix this. And Svelte works exactly like how Solid works today with the inconsistency on the spread. |
That thread is a neat read. The idea of It's a shame that browser and frameworks are so divergent here. I still like siding with the browser default, for the sake of "you can copy/paste HTML and it just works the same". But I suppose in actual practice, it doesn't really make much difference as long as you stick to standard attributes, so either way you'll get whitelisted to Boolean or pseudo-Boolean behavior as needed. The main practical difference you'd see is probably |
I think the one thing that we have going for us is that It's possible the right answer is no change. |
no change means <button draggable={true}>can drag</button>
<button draggable>can't drag</button> |
Yes which came up with the linked issue. I have very little problem with this. The argument is the browser doesn't work this way either. We are free to define the meaning of I guess I'm curious would you rather this be the case or that neither worked and you needed to do: <button draggable={condition() ? "true" : "false"}>can drag</button> I'm trying to gauge the cost of compromise here. Like is the concern that these look inconsistent? Or that it requires the knowledge of how draggable and boolean attributes work. |
honestly I am just realizing that draggable is an edge case, it is not really a boolean attribute so if we look at a real boolean attribute(presence base), we need to get to the equivalent of: "" | "checked" is to comply with the recommendation of the standard, but "true" also works I am not personally in favor of making I did like your proposed change, as it seem to strike a good balance. but realizing that
but then for Components do we expect prop.draggable so perhaps I am also starting to lean towards no change and any special edge case magic, should have special dedicated explicit syntax in my opinion( if its worth having). |
I'd indeed prefer "no change" over changing the meaning of But could we change |
I'm not sure it is possible to do just that. Because at that point all we know is |
Yeah I think Svelte is good company here. Let's leave this as is with one exception. I was handling it the Preact/React way in SSR. I will change that and hopefully that will be consistent enough. Dynamic probably needs to be part of the compiler. I'm not sure exactly what that looks like but I think that is the only way we deal with some of the desired gaps. |
Closing with 1.5 release. |
Continued in |
Slowly breaking this one into it's own component, things are still breaking even though I'm trying for them not to. I think the issue is with the getters and setters for the refs not being updated by way of `query()` and the `EditorElement.state` property, which I'm trying to build the state off of. https://docs.solidjs.com/reference/jsx-attributes/attr solidjs/solid#1101 solidjs/solid#1689 https://www.solidjs.com/docs/latest/api#attr___ https://www.reddit.com/r/MacOS/comments/12xt6jt/do_you_use_natural_scrolling/ https://www.reddit.com/r/apple/comments/tkxtn0/universal_control_should_have_an_option_to_use/ This commit was from the last day or so, wanted to come back with fresh eyes the next day to ensure everything it was doing was correct. With the things I changed, I think it's mostly right. The only problem is the state-related parts I was mentioning before.
Questions: How should JSX attributes
foo
andfoo={true}
behave for an HTML element, as in<div foo>
or<div foo={true}>
? Should the behavior differ for components and/or spreads?Current behavior in Solid:
Assume
const Div = (props) => <div {...props}/>
<div foo>
<div foo="">
<div foo="">
<div foo="">
<div foo={true}>
<div foo="true">
<div foo="true">
<div foo="true">
<Div foo>
<div foo="true">
☆<Div foo="">
<div foo="">
<Div foo={true}>
<div foo="true">
<Div foo="true">
<div foo="true">
The ☆ behavior (another consequence of
setAttribute
's string casting) is particularly counterintuitive, as it differs between HTML elements and component-wrapped elements. (It may also be an SSR discrepancy?) @fabiospampinato's observation of this weirdness is what spawned this exploration (in #templating channel, also with @lxsmnsyc).Relevant facts:
foo
to be equivalent tofoo=""
foo
is equivalent tofoo={true}
.foo
likefoo={true}
(attribute should accept Boolean value)foo
to HTML equivalent offoo="true"
unlessfoo
is on a whitelist of "Boolean" attributes, in which case it converts tofoo=""
. Here's a relevant list; note that there are some Boolean-like attributes which aren't actually Boolean. For example, React "correctly" convertsdraggable={true}
todraggable="true"
and "correctly" convertsasync={true}
toasync=""
.Desired properties:
foo
is always equivalent tofoo=""
for HTML/SVG elements (as in HTML 5). This is useful for copy/pastability of HTML, which the JSX spec considers important.foo
is equivalent tofoo={true}
(as in React and TypeScript)draggable={true}
is equivalent todraggable="true"
<div foo>
is equivalent toconst Div = (props) => <div {...props}/>; <Div foo>
We can't have all four properties.
draggable={true}
is equivalent todraggable=""
.Div
but notdiv
. It doesn't satisfy Property 4 because of ☆.Proposal:
I really like Property 1, and would propose gaining Property 4 by compiling
foo={value}
to essentially_el$.setAttribute('foo', value === true ? '' : value)
, wherevalue
is stored in a temporary variable if it's a general expression, with a similar modification to spreads. This would basically flip ☆, and also change those marked "!":<div foo>
<div foo="">
<div foo="">
<div foo="">
<div foo={true}>
<div foo="">
!<div foo="true">
<div foo="true">
<Div foo>
<div foo="">
☆<Div foo="">
<div foo="">
<Div foo={true}>
<div foo="">
!<Div foo="true">
<div foo="true">
(By contrast, React's approach of an attribute whitelist feels gross...)
The text was updated successfully, but these errors were encountered: