whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
8.11k stars 2.67k forks source link

New `indeterminate` attribute for <input type=checkbox> #6578

Open patrickhlauke opened 3 years ago

patrickhlauke commented 3 years ago

I'm wondering if there's any mileage in allowing indeterminate to be set using an actual attribute in HTML? i.e. being able to (statically) set a checkbox to be <input type="checkbox" indeterminate>, to match the same way this can be done but only for assistive technologies with <input type="checkbox" aria-checked="mixed">? again, it feels odd that it's possible to express this semantic concept in markup, but only for AT.

(split from https://github.com/whatwg/html/issues/5079#issuecomment-813111427)

domenic commented 3 years ago

Given that indeterminate is mostly cosmetic, this is mostly an easy change to make.

The only strange thing here would be the interaction with activation behavior: https://html.spec.whatwg.org/#the-input-element:dom-input-indeterminate-2

That temporarily sets the indeterminate IDL attribute to false before running activation behavior, and then back to its previous value (possibly true, possibly false) afterward. This means that making indeterminate into a content attribute would mean we'd have to be toggling content attributes during activation behavior, which is mostly unprecedented and seems a bit disruptive. (And would be observable with mutation events/observers.)

You could imagine other ideas like letting the content and IDL attribute get out of sync during activation, but that seems like it'd be likely to cause bugs in author code that otherwise assumes they are in sync.

patrickhlauke commented 3 years ago

we'd have to be toggling content attributes during activation behavior, which is mostly unprecedented and seems a bit disruptive

can't indeterminate work the same way as, say, <input type=checkbox checked> - in that the attribute in the markup only gives the initial state, and is then not updated ?

domenic commented 3 years ago

That seems particularly bad, given how much developer pain that feature of checked="" has caused over the years.

In other words, letting it get out of sync briefly during activation is bad. Letting it get out of sync forever after its value changes is really really bad.

patrickhlauke commented 3 years ago

agree it can be confusing, but then arguably at least the pain is on the same element, and it's the same kind of pain, so devs that found out the hard way that you can't rely on the attribute to check the checked state of a checkbox should not find it surprising that you also can't rely on the attribute for indeterminate and should always refer back to the property

domenic commented 3 years ago

Right now you can never rely on the attribute, and always have to check the property, to get the correct value for indeterminacy.

With your proposal you would never be able to rely on the attribute, and always have to check the property, to get the correct value for indeterminacy. But, there might be some buggy code that starts checking the attribute, because sometimes (before any script-induced changes or user clicks) the attribute is correct.

That seems worse to me.

patrickhlauke commented 3 years ago

My proposal is to be able to statically set the indeterminate starting state, the same way you can set the checked starting state. Say you want to provide a static example for "this is an indeterminate checkbox" for instance. with ARIA, I can do that easily. Not with vanilla HTML.

annevk commented 3 years ago

I guess there are two proposals:

  1. A indeterminate content attribute reflecting a defaultIndeterminate IDL attribute
  2. A indeterminate content attribute reflecting the existing indeterminate IDL attribute

The former is what @patrickhlauke proposes. The latter seems to be what @domenic argues for. The latter is more consistent with some new controls, the former more with <input>. Only the former would support form resetting well. The latter has some challenges whereby event dispatch would now potentially mutate the node tree...

gregwhitworth commented 3 years ago

We're looking into the checkbox scenarios with research that we'll be publishing to Open UI shortly and one we discussed was the usecases of indeterminate. While it is applied to a single checkbox it has to have the full relationship of some other dependency that isn't known. Based on the usecases we've reviewed we're having some initial thinking on a new grouping element that would enable what @patrickhlauke If you solely add an attribute you will still need to reach for JS to understand the relationships you mine as well throw on an unknown attribute or class to achieve it indeterminate. @patrickhlauke I'd be interested to hear your thoughts on that.

patrickhlauke commented 3 years ago

If you solely add an attribute you will still need to reach for JS to understand the relationships you mine as well throw on an unknown attribute or class to achieve it indeterminate

basically what I want to be able to do, easily - without having to reach for any JS on page load or anything like that - is to have the ability to write a static HTML example (think a library of components, showing their different styles/etc) to show "here's all the variants of checkbox - a readonly one, a disabled one, a checked one, an indeterminate one...". and, if i'm generating a form server-side with prefilled data, having the ability to already set one checkbox (which is a group checkbox for various sub-options) to be indeterminate at page load. I can achieve all the above for readonly, disabled, checked by just spitting out/adding the attribute in markdown, and I'd like to have the exact same ability for indeterminate. how it's then handled/what happens after the initial page load/once users interact with form controls is a different matter (though for consistency, it may make sense to do the same as what happens with the checked attribute, as it would be odd to have one kind of behaviour for one attribute, and a different one for another attribute).

it just feels philosophically weird to me that this sort of default state can't be expressed currently in pure HTML, but that if i add some aria-checked="mixed" i can express this semantically...but only for assistive technologies

gregwhitworth commented 3 years ago

@patrickhlauke at page load is a valid point for the need of a content attribute. I do agree with Domenic that the design should follow what's outlined in the TAG design proposal. This same scenario is being discussed regarding an initially open attribute for the new popup element in Open UI.

ghost commented 3 years ago

Another application of this attribute is static renderer output such as Github Flavored Markdown.. which we actually happen to be using on this website! Its a blocking feature request for indeterminate checkboxes on Github.

justinfagnani commented 2 years ago

I've seen a similar need with SSR'ing checkbox framework components: if the component uses a native input and also supports an indeterminate state, it can't SSR that, so it must loads JS and immediately hydrate in order to render correctly. Reflecting a defaultIndeterminate IDL attribute would at least fix that case.

domenic commented 2 years ago

Although I still feel proposal (2) from https://github.com/whatwg/html/issues/6578#issuecomment-817946060 is better, I am not opposed to proposal (1) if others do the relevant work and are OK with foreclosing on proposal (2). Proposal (1) is bad (even really, really bad per my earlier comments) but it's consistently bad with the rest of <input>.

scottaohara commented 2 years ago

Rather than a separate attribute, is there possibility for the checked attribute to accept an “indeterminate” or “mixed” value instead?

I ask because of the work going on with hidden right now where it will no longer be Boolean. And I realize this wouldn’t do anything in regards to the checked attribute getting out of sync, but that would still happen anyway if a new attribute was added. Eg input type=checkbox checked indeterminate> where now there’s not only a stale checked attribute, but it’s in conflict with the current indeterminate state.

annevk commented 2 years ago

Is it in conflict though? Although it appears as a tri-state, they appear to be two separate boolean states that can be toggled independently in implementations. If a checkbox is checked and indeterminate, it will be checked once it's no longer indeterminate. And if it was unchecked before, it will be unchecked after.

patrickhlauke commented 2 years ago

but from a practical point of view, it would still act as a tristate, so if kept as two separate booleans, you'd probably want to add extra logic/explanation that say the indeterminate state trumps whatever the checked state is when exposing to assistive technologies (i.e. always expose as "partially checked", regardless of whether the other boolean is true or false). seems more like some complexity you'd want to hide in the plumbing of this...

scottaohara commented 2 years ago

hi @annevk,

yeh i get what you're saying in regards to how it's implemented today, and your examples make sense. But in common situations where checkboxes like these are used, the examples assume that the user has 'resolved' the indeterminate state by checking or unchecking other checkboxes that return it to its previous state.

it is just as likely that a user unchecks other checkboxes and the indeterminate checkbox resolves to the opposite state of what it had previously been. A web page could actually load where a checkbox is in the indeterminate state by default... so what would the original state be then? (obviously whatever checked or unchecked state that was specified - or not - by the author. but the user likely wouldn't know that).

As far as how these are exposed to people visually (generally) and via assistive technologies, it's only a single state at a time.

I suppose someone could style their checkbox to have distinct visual indeterminate + checked or unchecked states. I can't think of an instance where i've seen it, but it's not out of the realm of possibility. But to AT, it's just one state.

Anyway, I realize the checked attribute may be too steeped in legacy for any changes to be made to it. Just figured with the modifications to hidden that are currently underway, was worth at least a mention here. Especially since, for better or worse, authors have been introduced to aria-checked="true | false | mixed", so it wouldn't be without precedent for them to expect the native HTML feature to behave similarly.

annevk commented 2 years ago

Even if not exposed to AT, it will be exposed to CSS and JS. So it's definitely a thing web developers (and at the very least us) will have to think about. We could say that for the purposes of the new attribute (value) indeterminate means one of checked and unchecked of course, but we cannot get rid of having four states in the overall model I think.

scottaohara commented 2 years ago

understood, and I wasn't trying to imply that HTML would / should get rid of anything. thanks

Christoph142 commented 2 years ago

I know this doesn't help with deciding for which implementation to go, but just as a side note: This would enable forms with mandatory checkboxes, where the user actively has to choose before submitting the form. IMHO this would be a good thing to have. Right now you can only force users to give consent by having the box unchecked. But in an indeterminate default state both giving consent and declining would be conscious actions.

annevk commented 2 years ago

Thanks for mentioning that, the difference between the four states is visible there as well. Depending on the state of checked, the next action will either check or uncheck the checkbox when it's indeterminate. I suspect bosses of developers of such forms to have an interest as to what the one-click result ends up being. Also, your expectation would not fall out naturally as it would also require changes to how validity works for checkboxes (depend on initial indeterminate-ness, I suppose).

Christoph142 commented 2 years ago

Yeah, I agree that this is for sure going to be a demand. That being said - correct me if I'm wrong - there is no implementation in any language that I ever used where clicking an indeterminate checkbox that acts as a grouping element unticks all subelements first, but it always ticks all of them before removing. So it might as well be valid having to resort to JS for such a (seemingly) edge case.

jakearchibald commented 2 weeks ago

Only the former would support form resetting well. The latter has some challenges whereby event dispatch would now potentially mutate the node tree...

I feel this point by @annevk hasn't been given enough weight (or maybe Shopify is one of the few places that uses form resetting).

If I server render an indeterminate checkbox, followed by a bunch of checkboxes in various states, it'd be nice if form reset could take everything back to its initial state.

So I feel like the right way is a defaultIndeterminate property that reflects to an attribute. That attribute can either be indeterminate to be consistently weird with value, or defaultindeterminate to be consistent with the rest of the platform.