Skip to content
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

CSS Toggles Proposal #6991

bkardell opened this issue Jan 26, 2022 · 8 comments

CSS Toggles Proposal #6991

bkardell opened this issue Jan 26, 2022 · 8 comments


Copy link

I'm not putting a spec since there isn't one in the wg yet, but on today's call @tabatkins introduced a proposal for comment and consideration that he's been working on for some time, but has recently had some fresh thought and interest. He asked if we could look at it and discuss perhaps next week and said that the chrome team was interested in doing some prototyping soon.

As this has been developing for some time, there has already been a non-trivial amount of discussion and I'd like to have an issue for this where we can link up some of those as people consider it.

Notably, part of the reason this came up again recently is some adjacent work and needs - as such there were 2 breakout sessions at TPAC on joint topics of the work in 'tabs' in openui, Microsoft's focusgroup proposal and this. Unfortunately the I cannot find a video of the presentation @travisleithead gave as well but the slides are available in and the minutes of 1 of those sessions at least are in ... I feel like the minutes exist for the other one too, but I don't have a link handy at the moment.

Copy link

Malvoz commented Jan 26, 2022

I cannot find a video of the presentation @travisleithead gave

Are you thinking of this video?
(found in

Copy link
Contributor Author

bkardell commented Feb 2, 2022 via email

Copy link

I'm actively working on an explainer and (js-polyfill driven) demo to provide more details around this proposal.

Copy link

Great proposal! It would be great if the concept of "element state" could also have an intuitive interface across HTML / CSS / JavaScript, such that HTML could define these states with simple attributes (other than just in the style tag, since it's not just a styling concern), and JS could update them with a simple interface. Similar to how checked has a simple interface across HTML / CSS / JavaScript. i.e. Like a checked state, many of these toggle states and their associated values would have utility across things like submitting form-field values (submitting the toggle value), or a state within a component to be accessed / set by JS, etc.

Copy link

I've been thinking about this proposal a lot (as my CSS nerd brain often does). I'm simultaneously super-excited about it and also concerned that it is not "broad" enough.

What I Mean

So, what this proposal effectively does is achieve (part of) something that HTML authors have failed to do thus far, at least making it to the browser, which is to natively be able to create "instances" of elements that are data-bound and stateful. This lack of "templating" has, of course, meant that this is been replicated ad nauseam in user land (e.g. React, Vue, Svelte, Angular, you name it).

On the one hand, CSS is a logical place for this functionality, because the abstraction of classes / selectors from elements means that you can create "instances" of this "toggle state" as an extension of the language. But this type of state is not necessarily presentational or only presentational.

Therefore, I can see a scenario where:

  • Some state is moved from React useState and other paradigms to CSS Toggle state, which sounds... good at first? except
  • This would likely, logically, be quickly hacked upon to provide "native state" to state which has nothing to do with presentation, or not only to do with presentation
  • The initial state value of one of these "instances" would likely be specified via the style tag in SSR or JS DOM updating, leading an awkward interface where "component state" is now a "styling" concern

Now, of course, the explainer addresses this directly! Saying (under Non Goals):

It should still be possible to use this feature in tandem with other web languages to represent/display those more complex application states in CSS

I get it. This group is addressing the needs of CSS, and not wanting to expand the scope beyond presentational. I guess what I'm wondering if there has been any discussion / exploration around something like a state attribute on HTML, which then acts as the toggle-root value. In other words, a more abstracted "state" model for HTML which can be read / changed by a CSS definition, but is also not so tied to CSS. Something that's more future-proof, I guess?

Maybe this just isn't possible at the moment, without the ability to create instances of HTML partials (Something like So maybe CSS is the only way to put this idea of "state" tied to "instances" in a declarative way. The idea of CSS being stateful (where the value is not a static value in the document) is just somewhat novel, so it feels like it could be more abstracted across the whole HTML/CSS/JS platform. 🤔 But I don't have any good alternative pitches, so I don't know.

Events and state

The other mild concern I have is that what causes a state change is implicit and not explicit. This seems to be addressed in the explainer under Other Component Interactions. I agree that something other than just click but being able to specify mousedown or mouseup etc would be key at some point.

Some questions

By the way, what happens when a state root "definition" gets redefined by a class that's added after that state value has been "triggered"? Especially if the number of states is now different, or the current state value is no longer valid, according to the toggle-root? Would it always reset? What if the current state value is valid but is in a different "position"? CSS is good for abstracting element definitions in some ways, but the cascade model means that "current state of X element" could be hard to reason about. I searched the explainer for "cascade" or "overrides" and couldn't find anything that addressed this directly.

Final thoughts

Just to reiterate, I think this is in general a really good idea! It's possible these other state concerns could be ironed out by some future HTML feature that would be 100% compatible with this. I just think it's worth thinking about it in broad (web platform) terms.

Copy link

In other words, a more abstracted "state" model for HTML which can be read / changed by a CSS definition, but is also not so tied to CSS. Something that's more future-proof, I guess?

The underlying mechanism here is to give elements a (deliberately very simple!) notion of "state", which can be created, manipulated, or reacted to by JS, and then have (a) a way for user interaction to change that state without script (the toggle-trigger property), (b) a way for CSS to respond to that state (the :toggle() pseudo) so authors can do presentational (and lightly semantic, when possible, like showing/hiding) things with it, and (c) a way to initialize the state without JS, so (a) and (b) can usefully function in no-JS situations (the toggle-root property).

This state is intentionally kept to just a non-negative integer or an ident; CSS can't reasonably handle much more than that with its syntax, on either the setting or reading side. To the extent that other systems can work under that limitation, they're free to use a toggle to store stuff on an element. If they're not using at least one of (a) or (b) above, tho, there's not really any benefit to it; just storing info in a JS property on the element is equivalent, more powerful, and more convenient. This is very intentionally not a generic whole-app state management system, as that is a far more complex problem and ties into far more things than CSS can interact with. It's just one corner that is useful on its own, and can form a useful appendage of larger state management systems.

The other mild concern I have is that what causes a state change is implicit and not explicit.

Spec will get cleaned up as we progress, and I expect it will grow more ways for users to interact with a toggle (like tying it to scroll snaps!), but the default is going to be "interaction" as defined by the host language. HTML already has activating an element as a well-defined concept.

By the way, what happens when a state root "definition" gets redefined by a class that's added after that state value has been "triggered"?

Nothing. At style resolution time we check that every element with a toggle-root has the named toggles defined on it; if not, we create them with the specified details. If they already exist, we just skip over them. This is a necessary part of the way we avoid styling cycles.

Copy link

matthew-dean commented Apr 25, 2022

@tabatkins That makes sense! I trust y'all have done deeper thinking on this than I have. Thanks for those explanations.

Nothing. At style resolution time we check that every element with a toggle-root has the named toggles defined on it; if not, we create them with the specified details. If they already exist, we just skip over them. This is a necessary part of the way we avoid styling cycles.

Oh interesting. 🤔 It would still be a useful thing to call out in the explainer, how that behavior works.

@astearns astearns added this to 9:00-10:00 in TPAC Friday 2022 Sep 11, 2022
@astearns astearns moved this from 9:00-10:00 to 11:45-12:30 in TPAC Friday 2022 Sep 16, 2022
@astearns astearns moved this from 11:45-12:30 to 1:30-3:00 in TPAC Friday 2022 Sep 16, 2022
Copy link

Minutes from CSSWG discussion
Friday, September 16th, 2022

14:31 <@fantasai> TabAtkins: and we're going to try as hard as possible on automatic inference
14:31 <@fantasai> TabAtkins: but we feel pretty strongly that this is a tractable problem, and a sufficiently large number of common ARIA cases can be inferred with good reliability
14:31 <@fantasai> TabAtkins: also fact that current way that it works is that practically zero percent ar correctly annotated
14:31 <@fantasai> TabAtkins: so literally anything we do will put us in a better situation!
14:32 <@fantasai> TabAtkins: but we think we can do genuinely good majoriyt of the time
14:32 <@fantasai> TabAtkins: hopefully strong majority of the time, will at least b eclose to right, vs literally nothing today
14:32 q+
14:32 — Zakim sees florian, Bert, fantasai, JakeA, miriam on the speaker queue
14:32 <@fantasai> astearns: fremy can you add some examples you're concerned with?
14:32 <@astearns> ack florian
14:32 — Zakim sees Bert, fantasai, JakeA, miriam on the speaker queue
14:32 <@fantasai> fremy: I think I did but can't find right now
14:32 <@fantasai> florian: This may be naive question, but seems to me the feature set overall is useful
14:32 <@fantasai> florian: but confused why parts of this other than toggle are in CSS vs HTML
14:33 <@fantasai> florian: state management seems like it belongs in the DOM
14:33 <@fantasai> TabAtkins: 2 basic reasons why, first is perennial thing that CSS is easier to use
14:33 <@fantasai> TabAtkins: Years ago I proposed Cascading Attribute Sheets
14:33 <@fantasai> TabAtkins: but that's not the main thing
14:33 <@fantasai> TabAtkins: toggle, a lot of things is not a semantic thing
14:33 <@fantasai> TabAtkins: what you toggle and how can change based on how you present
14:34 <@fantasai> TabAtkins: e.g. q&a might be always open on desktop, but compacted on mobile
14:34 <@fantasai> TabAtkins: so decision of when toggle is not something you make at authoring time but based on MQ
14:34 <@fantasai> TabAtkins: same reason why overflow is in CSS
14:34 <@astearns> ack Bert
14:34 Bert, you wanted to briefly explain a model for elements with multiple modes from some brainstorming a couple of years ago.
14:34 — Zakim sees fantasai, JakeA, miriam on the speaker queue
14:34 <@fantasai> Bert: I thought about how to solve this toggle problem several years ago, didn't get as far as Tab did
14:34 <@fantasai> Bert: my apologies for only hearing this proposal until recently
14:34 -> Hyperlinks in CSS - an attempt from 2002
14:34 <@fantasai> Bert: but does seem similar to what I tried to do, let me drop a link
14:35 <@fantasai> Bert: This doesn't deal with DOM APIs or a11y APIs, never got that far
14:35 <@fantasai> Bert: but maybe some ideas there that might be useful
14:35 present+
14:35 — tantek RRSAgent, pointer
14:35 — RRSAgent See
14:35 <@fantasai> Bert: also started with different perspective, as you see it's part of hypertext proposal of the time
14:35 <@fantasai> Bert: was trying to do what hypertext did, but open/close expand in place in the documen
14:35 <@fantasai> Bert: while trying to do that, thought what bout expanding to multiple states
14:36 <@fantasai> Bert: So this is much simpler than what Tab has, as I never got much interest
14:36 <@fantasai> Bert: doesn't define properties, only a pseudo-class selctor, the modes in this draft
14:36 <@fantasai> Bert: are just nubmers, 0 being normal and others being arbitrary
14:36 <@fantasai> Bert: you get as many as you declare
14:36 <@fantasai> Bert: many things are not specified, are implicit
14:36 <@fantasai> Bert: doesn't say how you change modes, presumably browser notices there are multiple modes and allos changing
14:37 <@fantasai> Bert: but spec doesn't say how that isdone
14:37 <@fantasai> Bert: how many modes is also implicit by what's in the stylesheet
14:37 <@fantasai> Bert: something figured out automatically
14:37 <@fantasai> Bert: ideally browsers notices if 2 modes are not different and merges them, but that might be hard to detec
14:37 <@fantasai> astearns: maybe best if Tab reviewed the proposal?
14:37 <@fantasai> Bert: yes, it's very short
14:38 <@fantasai> Bert: things like scope, which TabAtkins has, doens' thave. Scope is whatever reachable by selector
14:38 <@astearns> q?
14:38 — Zakim sees fantasai, JakeA, miriam on the speaker queue
14:38 q-
14:38 — Zakim sees fantasai, JakeA on the speaker queue
14:38 <@fantasai> Bert: which currently means only elements after
14:38 <@fantasai> Bert: no explicit scope
14:38 <@fantasai> Bert: that's it
14:38 <@fantasai> Bert: if Tab has interest in looking over, I can try to explain anything not clear
14:38 <@fantasai> TabAtkins: okay, looking now! Thanks!
14:38 <@heycam> fantasai: was wondering about ED
14:38 <@heycam> ... might be useful to keep track of hte history of what's going on with the draft
14:39 <@astearns> ack fantasai
14:39 fantasai, you wanted to ask why not ED
14:39 — Zakim sees JakeA on the speaker queue
14:39 <Rossen_> ack JakeA
14:39 — Zakim sees no one on the speaker queue
14:39 Also I can maybe try to do a history transfer, I suppose. There are tools that can reproduce commits like that.
14:39 <@fantasai> JakeA: In frameworks, they tend to want to declare what state they want toggles to be in, e.g. checked attribute
14:39 <@fantasai> JakeA: I see you have a place to state the initial value rather than current value
14:39 <@fantasai> JakeA: is it compatible with this ?
14:40 — @fantasai q+ to ask about semantics, CSS vs HTML and how to let authors do whichever is right
14:40 — Zakim sees fantasai on the speaker queue
14:40 <@fantasai> TabAtkins: There's an easy API to grab toggles and adjust in JS
14:40 <@fantasai> JakeA: not quite the same
14:40 <@fantasai> JakeA: I have used this hack that you talk about but done it for forms
14:40 <@fantasai> JakeA: is there any interaction of this with form data?
14:40 <@dbaron> you can look at element.toggles.get("togglename").value
14:40 <@astearns> JakeA: not compatible with React
14:40 <@fantasai> TabAtkins: not yet
14:40 <@fantasai> TabAtkins: right now, you can go check your toggles and paste into forms
14:40 <@fantasai> TabAtkins: no automatic links
14:40 I'm not clear, but couldn't react recreate the toggle with a new initial value?
14:40 <@fantasai> TabAtkins: but I think that's a reasonable thing to future
14:41 <@astearns> q?
14:41 — Zakim sees fantasai on the speaker queue
14:41 only if it blows away the element, flackr
14:41 if diffing doesn't blow it away, they can't change the value
14:41 — @dbaron q+
14:41 — Zakim sees fantasai, dbaron on the speaker queue
14:41 <@heycam> fantasai: this looks really cool, glad you're working on the a11y aspects
14:41 <@astearns> ack fantasai
14:41 fantasai, you wanted to ask about semantics, CSS vs HTML and how to let authors do whichever is right
14:41 — Zakim sees dbaron on the speaker queue
14:41 <@heycam> ... concerned people will use this for things that ought to be in the markup
14:41 <@heycam> ... e.g. the did I buy this ingredient yet list
14:41 <@heycam> ... that really ought to be a checkbox in the document, rather than an abstract thing
14:41 <@heycam> ... it's conveying information in the document, not just about visual state
14:42 <@heycam> ... not that we shouldn't have something in CSS where it is all about visual state, how do we make things that ought to be in the document be there?
14:42 q+
14:42 — Zakim sees dbaron, ydaniv on the speaker queue
14:42 <@fantasai> fantasai: I challenge the notion that "this should be in the document" ves here.
14:42 <@fantasai> s/fantasai/TabAtkins
14:42 <@fantasai> TabAtkins: The effect on any tool that cares about it semantically shoudl be the same
14:42 <@fantasai> TabAtkins: CSS already affects a11y tree in certain ways
14:42 q-
14:42 — Zakim sees dbaron on the speaker queue
14:42 <@fantasai> TabAtkins: affects whether things show up
14:42 <@fantasai> TabAtkins: so the effect of CSS on a11y and semantics in non-visual presentations is already there but ill-defined
14:43 <@fantasai> TabAtkins: topic in ARIA is wanting ot officially define a CSS a11y tree mapping
14:43 <@fantasai> TabAtkins: describing CSS effects on it, including toggle
14:43 <@heycam> fantasai: it's not just that
14:43 <@heycam> ... let's say I want to capture the current state of the document to save for later
14:43 <@heycam> ... would be ideal if you could just spit out the DOM
14:43 <@heycam> ... things that represent the state of the document, not just where you're scrolled to, but information that's being stored. that should be in the DOM
14:44 <@heycam> ... if you're storing just to adjust layout, that's one thing, but if you're storing the state of whether you bought an ingredient in CSS, that's not right
14:44 <@heycam> fantasai: we should be encouraging good practices, designing our technology to make it easy to do the right thing
14:44 <@heycam> TabAtkins: I don't think we should be concerned with serializing DOM state
14:45 <@heycam> fantasai: the arch of the Web is that data is in the DOM, and styling is in CSS, and there are places where boundaries are blurred, but we try our best to put things in the area they belong
14:45 <@florian> +1 to fantasai
14:45 <@heycam> ... I can see use cases for toggles that are solely in CSS< because it's how you're displaying the page, and only about the visual presentation, but I'm seeing some of the examples in the spec and it's about the underlyingh information in the document
14:45 <@heycam> ... I'm concerned about us doing that in a way that encourages authors to do the wrong thing
14:45 <@fantasai> dbaron: Might be worth looking at examples in the explainer rather than spec
14:45 <@fantasai> dbaron: I agree with you that there are a bunch of things that you can do with CSS Toggles that don't belong in CSS
14:46 <@fantasai> dbaron: A lot of other features in CSS have that quality
14:46 <@fantasai> dbaron: I tihnk we should try to encourage people to make the right distinctions
14:46 <@fantasai> dbaron: but I think there are a lot of things that toggle can do that do make sense in CSS
14:46 <@heycam> fantasai: I wasn't arguing that
14:46 <@fantasai> dbaron: I do think we should make the documentation reflect good usage
14:46 <@heycam> q+
14:46 — Zakim sees dbaron, heycam on the speaker queue
14:46 <@astearns> ack dbaron
14:46 — Zakim sees heycam on the speaker queue
14:47 <@fantasai> dbaron: I have implemented a prototype of much of the spec in Chromium, still some a11y and activation that Tab is trying to work out
14:47 <@fantasai> dbaron: and also haven't implemented toggle-visiblity, quite interesting and useful
14:47 <@astearns> ack heycam
14:47 — Zakim sees no one on the speaker queue
14:47 <@fantasai> dbaron: but that's the main thing I've been working on the past month or so
14:47 — @dbaron q+
14:47 — Zakim sees dbaron on the speaker queue
14:47 <@fantasai> heycam: comments about state living in CSS or the DOM make me wonder if the design of this feature could be extended to do either
14:48 <@fantasai> heycam: and you could design it so that e.g. data attributes in teh DOM are used to store state
14:48 <@fantasai> heycam: that won't help authors select the right one, you would have to select the right storage mechanism but maybe that's one alternative
14:48 <@fantasai> TabAtkins: You can get the toggles off the element in the DOM, but not HTML syntax
14:48 <@fantasai> TabAtkins: I don't think we should care about that
14:48 <@fantasai> TabAtkins: HTML is HTML's concern
14:48 <@fantasai> heycam: I would compare it to how form controls work, and checked attributes get added and removed and ???
14:49 <@fantasai> TabAtkins: neither of those happen
14:49 <@fantasai> TabAtkins: checked only sets the initial state, neither of them are updated live
14:49 <@fantasai> TabAtkins: it's annoying :)
14:49 <@astearns> ack dbaron
14:49 — Zakim sees no one on the speaker queue
14:49 <@fantasai> dbaron: I realized I didn't finish
14:49 <@fantasai> dbaron: the prototype I have is intended to be experimental, goal of implementing was to figure out whether it addresses bunch of use cases we think it addresses
14:49 <@astearns> q+
14:49 — Zakim sees astearns on the speaker queue
14:49 <@fantasai> dbaron: and also to help sort out some of these a11y issues
14:50 <@fantasai> dbaron: to have something that we can test it on, not implementing because we want to ship
14:50 <@fantasai> TabAtkins: it's part of some of our medium-term plans, but not short-term shipping plans
14:50 <@fantasai> dbaron: I also have to go now!
14:50 <@fantasai> astearns: Wanted to talk about next steps, Tab you're going to be working on things, and some point will ask for ED?
14:50 <@fantasai> astearns: wondering whether the point, should we have a joint CSS-ARIA meeting?
14:50 <@fantasai> astearns: since both groups will have concerns
14:51 <@fantasai> TabAtkins: I wouldn't be concerned, will be talking with ARIA anyway
14:51 <@astearns> ack astearns
14:51 — Zakim sees no one on the speaker queue
14:51 +1 to joint CSS-ARIA meeting for toggles
14:51 <@fantasai> astearns: thanks for presenting this, looking forward to it
14:51 <@fantasai> Topic: CSS Contain
14:52 <@fantasai> florian: before we dive into issues, goal of this session is to republish
14:52 <@fantasai> florian: last publication was December 2020
14:52 <@fantasai> florian: many changes editorial, many have WG resolution
14:52 <@fantasai> florian: but while reviewing the whole thing for publication, which I hoped I could just do
14:52 <@fantasai> florian: I found 3 changes which either don't have a resolution or not fully backed
14:52 <@fantasai> florian: so I'm hoping the WG to agree to publish, possibly with these 3 issues being closed
14:53 <@fantasai> florian: They've been in the ED for awhile, they've had some discussion, so hopefully we can resolve to publish and if something is wrong will publish later

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
No open projects

No branches or pull requests

7 participants