bigskysoftware / htmx

</> htmx - high power tools for HTML
https://htmx.org
Other
38.19k stars 1.3k forks source link

Boolean attributes with no value should behave as if it were set to `="true"` #2414

Open infogulch opened 7 months ago

infogulch commented 7 months ago

There are several attributes that accept boolean "true" values. If such an attribute is present with without a value it should behave as if it were set to true. I.e. writing <a hx-zzz> should be equivalent to <a hx-zzz="true"> for boolean attributes. This would save space and make it nicer to read. Some examples:

<div id="alerts" hx-swap-oob>
    Saved!
</div>
<a hx-boost href="/hello">Click me</a>

Are there any technical or historical reasons why to not do this?

schungx commented 7 months ago

I believe this goes against the normal HTML practice for browsers, where attributes without a provided value always gets the empty string.

Upon submission, a check-box (for example) will submit the string on when it is true (omitted if it is false). This is just how browsers deal with HTML from the very beginning.

Deviating from this standard will immediately confuse many people.

infogulch commented 7 months ago

Ok so make it so that empty strings behave the same as specifying ="true".

schungx commented 7 months ago

In this case, there are other possible values for hx-swap-oob other than true. Therefore hx-swap-oob is not boolean.

In HTML, a boolean attribute is false if omitted, true if set to any value. This is obviously not true here.

infogulch commented 7 months ago

An attribute with a meaningful empty/unset value has precedent in HTML today, in the iframe sandbox attr. If empty, it defaults to applying all restrictions.

I'm proposing a similar behavior for related htmx attributes, where the empty/unset value is assigned a common semantic meaning.

06b commented 7 months ago

Since you asked if "there any technical or historical reasons why to not do this?" — in regard to the topic of Boolean attributes, according to specifications

The presence of a boolean attribute on an element represents the true value, and the absence of the attribute represents the false value.

If the attribute is present, its value must either be the empty string or a value that is an ASCII case-insensitive match for the attribute's canonical name, with no leading or trailing whitespace.

Note The values "true" and "false" are not allowed on boolean attributes. To represent a false value, the attribute has to be omitted altogether.

As @schungx pointed out, there are other values for hx-swap-oob and therefore hx-swap-oob is not boolean. Also according to the specifications, hx-boost also isn't a boolean attribute as the "true" & "false" values aren't allowed on boolean attributes.

hx-swap-oob & hx-boost more likely falls under the Keywords and enumerated attributes

Some attributes, called enumerated attributes, take on a finite set of states. The state for such an attribute is derived by combining the attribute's value, a set of keyword/state mappings given in the specification of each attribute, and two possible special states that can also be given in the specification of the attribute. These special states are the invalid value default and the missing value default.

Note Multiple keywords can map to the same state.

Note The empty string can be a valid keyword. Note that the missing value default applies only when the attribute is missing, not when it is present with an empty string value.

And you can read the linked specifications where on determining the state of an attribute.


Now that we've answered that...

I'm proposing a similar behavior for related htmx attributes, where the empty/unset value is assigned a common semantic meaning.

So, you've listed hx-swap-oob & hx-boost as the examples, at first hx-boost made sense, but honestly, I don't find myself having to type hx-boost="true" that often since it can be placed on a parent element and is inherited. Example from the htmx docs:

<div hx-boost="true">
  <a href="/page1">Go To Page 1</a>
  <a href="/page2">Go To Page 2</a>
</div>

Now under your proposal, (assuming the common semantic meaning for hx-boost would be true) then we could assume the example would be as follows:

<div hx-boost>
  <a href="/page1">Go To Page 1</a>
  <a href="/page2">Go To Page 2</a>
</div>

So, if I wanted to disable hx-boost for example on the Page 2 link, could I do this?

<div hx-boost>
  <a href="/page1">Go To Page 1</a>
  <a href="/page2" hx-boost="">Go To Page 2</a>
</div
yawaramin commented 7 months ago

There is precedent in HTML that an enumerated attribute can be written without a payload: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable

...true or an empty string, which indicates that the element is editable....If the attribute is given without a value, like <label contenteditable>Example Label</label>, its value is treated as an empty string.

infogulch commented 7 months ago

So, if I wanted to disable hx-boost for example on the Page 2 link, could I do this?

The documentation says:

Notes

...

  • Selectively disable boost on child elements with hx-boost="false"

So that code would have to look like this:

<div hx-boost>
  <a href="/page1">Go To Page 1</a>
  <a href="/page2" hx-boost="false">Go To Page 2</a>
</div>

Thus, this change should not break compatibility with existing uses.