w3ctag / design-principles

A small-but-growing set of design principles collected by the TAG while reviewing specifications
https://w3ctag.github.io/design-principles
176 stars 46 forks source link

New principle: The value of HTML boolean attributes doesn't matter #451

Open LeaVerou opened 1 year ago

LeaVerou commented 1 year ago

This was brought up in https://github.com/openui/open-ui/issues/800

We should formalize it as a design principle that in HTML, boolean attributes are true by presence and false by absence — the exact value does not matter. ARIA is an outlier here, and we should not repeat this.

FWIW I don't think it's actually a good pattern, and introduces a lot of warts, but this ship has sailed long ago, and inconsistency with the existing precedent would be more costly.

alice commented 1 year ago

The ARIA "true/false" issue is a tricky one; see https://github.com/w3c/aria/issues/1110#issuecomment-616806811 for example. Obviously, as you say, it's too late to change it now anyway.

As far as the principle is concerned, does it need to be a design principle, or does the Reflecting content attributes in IDL attributes guidance for boolean attributes suffice?

LeaVerou commented 1 year ago

As far as the principle is concerned, does it need to be a design principle, or does the Reflecting content attributes in IDL attributes guidance for boolean attributes suffice?

The design principle would be about the HTML syntax.

annevk commented 1 year ago

This feels too detailed to be a design principle. HTML already codifies what a boolean attribute looks like (and contradicts itself with various boolean-like attributes that are defined as enumerated attributes, which is what we should migrate ARIA towards).

A design principle to me would be something more akin to "follow established precedent (unless you have a very good reason not to)".

LeaVerou commented 1 year ago

This feels too detailed to be a design principle. HTML already codifies what a boolean attribute looks like (and contradicts itself with various boolean-like attributes that are defined as enumerated attributes, which is what we should migrate ARIA towards).

A design principle to me would be something more akin to "follow established precedent (unless you have a very good reason not to)".

We currently have both types of principles in the Principles document. E.g. 3.2. Use space-separated attributes for short lists of values, separate elements for longer lists or 6.4. Accept optional and/or primitive arguments through dictionaries are in the same level of abstraction, and there's several low-level principles around naming as well. I'd say our principles are 70% low-level and 30% higher level, abstract stuff (mainly chapters 1 and 2). And for good reason: general, abstract principles are nice, but without concrete, specific principles, they are open to interpretation, so it's hard to achieve any level of consistency in the platform.

hober commented 3 months ago

As far as the principle is concerned, does it need to be a design principle, or does the Reflecting content attributes in IDL attributes guidance for boolean attributes suffice?

The design principle would be about the HTML syntax.

Why just HTML syntax? Would we want boolean attributes to work differently in SVG and MathML? I hope not.

plinss commented 3 months ago

We should also document the CSS principle to not use booleans, and perhaps write guidance about when enum values would be more appropriate (extensibility).

LeaVerou commented 2 months ago

One problem is that both patterns are very suboptimal. The HTML pattern provides no way to specify false, meaning all boolean attributes need to be false by default leading to double negatives like element.disabled = false. The ARIA pattern is clumsy, more technical, and incompatible with the rest of HTML.

When thinking about this I did wonder if it might actually be web compatible to bridge the gap by specifying that boolean attributes are true for any value except "false". That would allow specifying e.g. aria-checked without a value or disabled="false". I knew the odds that this would be web compatible would be slim, but it would fix such a big wart I thought it was worth at least checking out. So I reached out to @rviscomi to figure out two questions:

  1. How many HTML boolean attributes are explicitly specified to ="false"?
  2. How many ARIA boolean attributes are specified with no value?

The results are not encouraging, but I thought we should still have the data. If anything, perhaps following up on the actual uses might uncover that these are all authoring mistakes that would actually be improved by changing the behavior.

1. How many HTML boolean attributes are explicitly specified to ="false"?

SQL query ```sql SELECT LOWER(boolattr) AS boolattr, COUNT(DISTINCT page) AS pages FROM `httparchive.all.requests`, UNNEST(REGEXP_EXTRACT_ALL(response_body, r'(?i)(checked|disabled|selected|hidden|open|async|autoplay|muted|loop|defer|ismap|nomodule|novalidate|readonly|required|reversed)=[\'"]?false[\'" >]')) AS boolattr WHERE date = '2024-03-01' AND client = 'mobile' AND is_root_page AND is_main_document GROUP BY boolattr ORDER BY pages DESC ```

Answer: 18% of pages, though this happens far more with some attributes rather than others:

boolattr pages pct pages
async 1,702,692 10.5047%
hidden 531,849 3.2812%
disabled 472,752 2.9166%
required 228,607 1.4104%
selected 204,767 1.2633%
autoplay 166,398 1.0266%
loop 55,718 0.3438%
open 45,117 0.2783%
checked 26,138 0.1613%
readonly 3,995 0.0246%
muted 3,247 0.0200%
defer 968 0.0060%
novalidate 124 0.0008%
reversed 91 0.0006%
ismap 65 0.0004%

2. How many ARIA boolean attributes are specified with no value?

SQL query ```sql SELECT COUNT(DISTINCT IF(REGEXP_CONTAINS(response_body, r'(?i)aria-(checked|disabled|selected|expanded|haspopup|hidden|multiline|multiselectable|required|readonly|pressed|grabbed)[^=]'), page, NULL)) / COUNT(DISTINCT page) AS pct_pages FROM `httparchive.all.requests` WHERE date = '2024-03-01' AND client = 'mobile' AND is_root_page AND is_main_document ```

Answer: 3.1% of pages. Again this varies by attribute:

aria_attr pages pct pages
expanded 251447 1.5513%
hidden 191595 1.1820%
selected 107823 0.6652%
disabled 45106 0.2783%
haspopup 34693 0.2140%
pressed 26057 0.1608%
required 8254 0.0509%
readonly 5648 0.0348%
checked 3130 0.0193%
multiselectable 1248 0.0077%
multiline 250 0.0015%
grabbed 207 0.0013%

Besides HTML usage, such a change would likely not be web compatible as it would break a lot of JS that checks for boolean attributes by doing hasAttribute().