-
Notifications
You must be signed in to change notification settings - Fork 8
Non-boolean states #4
Comments
|
I still question whether this feature has many use cases. None of the existing pseudo-functions match states, and no libraries have desired to add this. See w3ctag/design-reviews#428 (comment) for the direction I'd rather see, which is not connected to custom elements at all. As such I think design work here is a bit premature. |
Valid; I'm mainly doing some design work here to satisfy the CSSWG's concern that the potential extension of boolean into non-boolean is reasonable. I think avoiding this in the core spec right now is the right move. |
Your feedback in the TAG review also makes the point more forcefully that a lot of the functional pseudo-classes that currently exist are not just attribute-like, with a name/value mapping, but rather do some complex gymnastics on both the argument and on the element to figure out matching. (Really, the only example close to this simplicity was That said, several of our pseudo-classes could very reasonably have been done in this manner instead, such as :current/:future/:past instead being a That sort of namespacing is nice conceptually for authors: it groups related things together so it's easier to understand what it applies to; it avoids semantic clashes like :empty vs :blank ( So, I do think there's useful space here to explore for an attribute-like state pseudo-class, in addition to more complex Houdini-driven custom pseudo-classes. |
Hmm, I'd find that pretty confusing as an author, personally. All existing pseudo-functions are universal, but then the CSSWG starts introducing new pseudo-functions which are state-like? Just when I got used to states all being normal, non-functional pseudo-classes? Separate from the design of custom pseudo-classes and pseudo-functions, I'd encourage consistency going forward for future built-in things. Namespacing via dashes makes more sense to me than namespacing via functional notation. |
If we designed them today, we wouldn't have them as precedent for doing them a different way. ^_^ |
I'm OK with the attribute remaining simply Let's simply make it a real maplike (not set-ish like DOMTokenList):
If we want to be a bit more setlike we can add
This supports non-boolean states while keeping very similar API ergonomics to DOMTokenList and can easily be expanded to non-string types (including callback functions, though I don't think calling back to user code during selector evaluation is going to be a good idea unless we can severely constrain the callback). I don't have a strong need to support non-boolean states in V1, but frankly I also don't see a good reason not to. It's not like it adds a ton of complexity, and there are use cases, though I accept they're not the most common. Building an API that's geared towards booleans now at the expense of extensibility is just going to bite us down the road and create yet another awkward API when it's inevitably extended. Let's please stop repeating the same mistakes. @domenic I think you're making an artificial distinction between pseudo-classes and pseudo-functions (which isn't actually a thing). Pseudo-classes can have a simple string, or a functional syntax. They can also match state or be used to perform selector math, these concepts are orthogonal (and given a time machine, I'd change the syntax of those like we changed pseudo-elements to be different). There are examples of both functional and non-functional notation being used for both already in CSS. No one is proposing using this feature for adding selector math, if we ever go down that road it'll have to be a very different approach. There is nothing preventing adding additional state matching pseudo-classes that use functional notation. @tabatkins random thought, not sure if this is a good idea, but one way to get |
This makes the decision of whether the pseudo-class is a function or not a consequence of whether it's currently set to a value. Either it's impossible to represent a pseudo-class with empty arguments (like It also means that either we have to make the signature If we instead use DOMTokenList for now, and later add a map, it means we can distinguish between
Strong dislike. ^_^ Anything more complicated than simple keyword matching should be done in a Houdini API, I think. |
Right, by design. We can alternatively have the non-function psuedo-class syntax match whenever the state is present in the map, regardless of its value. I think that would actually be the better approach.
If we really need to distinguish between
Which I also proposed, defining how string state values work isn't hard. Let's just do it. So far we've spent significantly more time discussing whether or not to do it than it would have taken to do it. We can also add Another alternative would be to make the map signature
And having states defined in both
I'm actually not a fan of it myself, but thought I'd throw it out there. Food for thought if nothing else. I'd also prefer a Houdini API, but adding user JS code to selector matching is going to be a hard sell, at least a regex is bounded. It's also not clear if lang-like/regex functionality is needed at this point. |
No, see my own explorations up above, about a syntax that allows multiple tokens (a la our defunct Not to mention, once we know we're doing functional pseudo-classes, we'll want a plan for handling more complex ones in the future; "Houdini will handle it" isn't an answer. ^_^
A half-map-half-set API would be novel to the web platform so far, and I don't want its design to be the result of a quick and dirty syntax exploration in an issue not dedicated to the matter. If we produce this now, we'll probably want to use it in other things in the future, and so I want to make sure we get it right. |
I would strongly object to adding such functionality to this API for the reasons I've stated previously, about how I think they belong separate and the pseudo-functions should not be connected to custom elements. |
I strongly object to the characterization of your objection (I agree with @plinss that CSS does not draw any significant distinction between functional and boolean pseudo-classes, and we shouldn't invent such a distinction for custom elements), but we can at least agree that we shouldn't add that to the API right now. ^_^ |
I guess we'll have that debate if it becomes important, but I'll assume for now that for one reason or another we'll avoid tying custom pseudo functions to custom elements, regardless of the reason. |
I never said it was finished, just that it's not rocket science and isn't a significantly hard problem to force a bunch of smart people to stop working on it and give up. All I've ever been asking for here is a reasonable amount of effort to explore alternative APIs that are more future proof than a DOMTokenList. Aside from this conversation I've yet to see that. Let's keep it going.
I agree. Let's give it some thought.
What I proposed isn't really a half-map-half-set, it's just a map with one convenience method (and you yourself suggested a maplike above). I'm also not proposing we all accept a quick and dirty exploration without giving it all due consideration. I'm just trying to start a conversation here that I've been asking to have happen for a long time. I'm more than open to alternative proposals or improvements/iterations of mine.
Agreed. Let's do that. |
Given HTML has boolean attributes yet we don't have two DOM API for accessing boolean attributes and non-boolean attributes, I don't see why we want to have two different APIs for boolean states and non-boolean states. It would be inconsistent with the rest of Web platform, and it's really awkward having to iterate over two different properties in order to process boolean vs. non-boolean, and |
I think we don't need to stick with
I prefer We can disable the maplike-provided |
If people are cool with the boolean Map, then I won't object; I just thought it felt clumsy, but it's not a killer objection. Happy to go with consensus here. So that still brings up the further question: when are parentheses allowed? First, from a syntax perspective, we have to allow parens in all cases. We'll be under the same constraints as registered custom properties, where we don't want to have to re-do parsing after each new definition. So all custom pseudo-classes, boolean or functional, will be syntactically valid; the registration just determines whether they match or not. We just need to decide whether we automatically make matching choices for the author based on their registration, or not. For booleans, we have a simple choice:
Passing arguments, like For functional, we've got more choices:
I think only b2+f1 are inconsistent; the other five possible combinations are reasonable. Current CSS pseudo-class design points toward b1, as none of the boolean pseudo-classes can be written in functional form; any of the f options are possible, since none of the functional pseudo-classes are valid to use with no arguments, so any of the behaviors could potentially be what they'd use in such a case. However, @fantasai and I have created designs in the past which would require f2 or f3: the aforementioned @hober pointed out that consistency with HTML attribute design points to b2+f2, as boolean attributes are equivalent to passing an empty value; Personally, I think I prefer b1+f2, tho I would be fine with anything that wasn't f1. I prefer b1 because of consistency with existing CSS, and because something being boolean or functional seems like an interface decision that the component user should be familiar with if they're using it. The presence of parens implies that something is valid to put within them, and if that's not on the table at all, I think we should reflect that in the allowed syntax. I prefer f2 over f1 because I've come up with designs that want to allow boolean form being equivalent to functional with no arguments, and preventing that up-front seems annoying and limiting. I prefer f2 over f3 because I don't see a good reason for a component author to create a pseudo-class that allows an empty argument, but doesn't want the boolean form to be equivalent to that. I can't write good guidance on when one should turn such an option on or off, so I don't think we should offer the option at all; confusing or unclear switches are bad API design. |
My objection to any API which treats custom psuedo-classes and custom pseudo-functions the same remains, including using a map-type API or allowing function syntax to count as the equivalent state syntax. |
Both of those are pseudo-classes; are you trying to draw a distinction more aggressively than CSS itself does? CSS doesn't assert any fundamental difference between |
I am trying to draw the same distinction that CSS currently does in practice, even if the CSS specs do not currently use two different terms. The existing CSS specs have two very distinct classes of things, which act differently and are used in different ways, and we should preserve that going forward. I understand in the past you have worked on designs to use the pseudo-function syntax for states, which would blur the distinction, but thankfully those never shipped, so the distinction remains. |
I assure you that CSS does not draw such a distinction in practice or in theory. It happens to be the case that none of the currently-existing functional pseudo-classes are defined in such a way that passing no arguments is a reasonable thing to do. That's an accident of history, not an intentional choice we've made. The boundaries of CSS design in general would be fine with such a thing existing. Unlike languages like JS, where there's a meaningful distinction between a function and its return value, in CSS the arguments are just additional clarification to the operation of the pseudo-class as a filter. |
I think it's an important part of the mental model of web developers. That aside, I don't think custom elements should be controlling selector functions operating over them. That should be another API. Custom elements should be able to set custom boolean states on themselves, which are exposed to CSS in some way. (I don't care if the way they are exposed is spelled This is doubly important because no web developers have asked for the custom functions capability, nor do we have any use cases presented where it would be helpful. We should keep the design focused on use cases, not some idea of theoretical symmetry based on the fact that CSS specs uses the same word for two different syntaxes and mental models. |
This distinct mental model exists only with you, I think. For things that have an existing direct boolean/functional correspondence, The aforementioned abandoned proposals from Elika and I used named that were appropriate on their own and had reasonable empty-arg semantics. @annevk (among others) has proposed a These are all reasonable things to do, and there's nothing fundamental about the syntax that would suggest we should instead, say, have a |
This is correct, and why we're not currently designing such a thing. We're just making sure that the current design is future-friendly to functional pseudo-classes, and a maplike that accepts some sort of object representing a registration works just fine there. (The existing Houdini APIs that register stuff do so by hiding the map in a global and just giving you the ability to add/remove from it indirectly, but fundamentally it's still just a map sitting there, holding name->registration pairs. We could match that here by hiding the map in the shadow tree and giving you indirection mutation APIs, but that seems unnecessarily obtuse when we want to ensure you have an easy way to toggle boolean states, at least; we'd just end up reproducing a bunch of API that maps/sets already have.) |
I think that's incorrect, because I think the design should be fundamentally different for function-matching vs. setting boolean states. |
Do you have reason to suspect that the design for handling functional pseudo-classes (presumably delegating to a worklet, like other similar things) would be fundamentally different than the existing designs for Custom Layout and Custom Paint, and the planned designs for Custom Functions and Custom Properties (v2)? All of those are just a name->registration map, we just don't expose the map directly. (At least partially because we don't expect there to be a good reason to manipulate the map besides adding registrations and perhaps removing ones you put in, and no good reason to iterate the map either. The same is likely true of the registrations for functional pseudos, but boolean pseudos will want easy manipulation of the value.) If you do have such a reason, hearing it would be great. ^_^ Otherwise I'm going to proceed on the assumption that the design will be similar, and a Map is appropriate. |
I think none of custom functional pseudo-classes, custom layout, or custom paint, should be tied to ElementInternals, like custom element boolean states are. |
Oh, that's not the direction I thought you'd take. So you think that custom elements should be disallowed from exposing information in a way similar to |
Because I think element states are fundamentally different from things like |
The fact that it has not happened for any element in the history of HTML so far, nor has it happened for any custom elements created by web developers participating in these threads, nor has anyone been able to come up with such an example. |
Even if, should we find ourselves 10 years out with no one, ever, having used a non-boolean custom state, a map-like API with a simple |
I fundamentally disagree with this. The point of custom elements in general, and this feature in particular, is to achieve HTML parity. I'm not sure how to cross such an ideological gap with you, so I won't wade in further. |
So custom elements should never be able to do anything HTML can't already do? And are not meant to extend the platform in any way whatsoever? Then why do they exist? They seem like an awful lot of work for some syntactic sugar. (And by the way, there's nothing preventing HTML elements from expressing non-boolean state via pseudo-classes.) Yeah, that's quite a gap. |
Please do not rephrase others' words in intentionally misleading ways. I will no longer be participating in this thread given the conduct exhibited therein. |
I did not. I characterized my understanding of what you wrote. If that understanding is incorrect, please rephrase. |
I don't have a strong objection to redefining A normal map called with I think this only becomes significant depending on how we define the selector to behave. e.g. given real map-like storage, does One option is to define Another option is to make the interface set-like for now and add |
Right, there's definitely not always an obvious thing, and many (most?) functions won't have anything reasonable to do without arguments. (None of the current built-in functional pseudo-classes do!) So if your function requires an argument, passing no args will just fail to match due to grammar mismatch, same as if you passed random garbage. (And the same applies if we choose option f2, and someone uses
This is a misstatement of the actual point, and as such can't be used to make the point you think you are. Custom elements and the associated feature suite are meant to achieve overall interface feature parity with HTML - anything you can do to/with a built-in HTML element, you should be able to do to/with custom elements (such as invoke them with a meaningful tagname, produce them via the parser, interact with forms, appear in the a11y tree, etc). The point of that feature parity is to allow people to use custom elements to achieve things that HTML will never do, and do so in a way that both feels natural, and interoperates with the rest of the ecosystem as smoothly as possible. All of this is moot for this topic, of course; we're not discussing any novel syntax here. You've been, for a reason that still eludes me, trying to assert that functional pseudo-classes are restricted to a particular use-case (using surrounding DOM-tree information, rather than internal element info), presumably based on overfitting to the current set of established selectors in the Selectors 4 spec, and then using that to argue that custom elements thus will never need to use such a syntax. That's simply not true, however, as I've repeatedly said, and Peter has supported as well. Trust the experienced CSSWG members to know the history and design space of Selectors better than you, please. ^_^ |
Yeah, using
(Note: both of those are My intuition is that it's useful for authors to make it only match when the boolean is specifically (By hand, toggling is |
Correct, my bad.
I'm vacillating on this. I think I can argue it being intuitive or surprising for authors either way. I'd like others on the CSSWG to chime in. e.g. given purely string states, |
What do you mean by |
I meant it as a wildcard, e.g. |
Oh, and unfortunately this isn't possible, or else I'd be all for it. ^_^ The default iterators for sets and maps are different; sets iterate thru their values, maps iterate thru their items (
Ah, kk. I won't speculate too much on that, as we have no idea what the eventual interface for non-boolean states will be like. We'll figure that out when we get to it; there's no requirement to solve it right now. |
(I presume you're actually replying to the 'use a Set for now' comment instead.) Yeah, right. I knew that but forgot, which is why I proposed a Map with the addition of |
I strongly agree with @domenic 's position here. I don't think there is a realistic use case that requires functional syntax for states. It's true that CSS does not distinguish pseudo-classes that are states from other kinds of pseudo-classes that are, essentially, complex combinators. Likewise, CSS does not distinguish pseudo-elements that are parts of an element from other kinds of pseudo-elements. But for custom elements, the specific real needs to do the kinds of things built-in elements can are limited to states and parts respectively. No one has presented a realistic example of a state that can't be represented with a simple tag. These states are like the states of a finite state machine. They are not functions that take input and do complex evaluation. We should not add complexity to the web platform for hypothetical use cases, and that's all anyone has provided so far. It's true that some enumerated sets of states could be expressed as a function that takes a small fixed set of values. But providing a second possible syntax for something is also not a good reason to add complexity to the web platform. Finally if there need to be other kinds of extension points to pseudo-class or pseudo-element syntax, then let's evaluate those on their own merits. |
It seemed pretty clear to me that Domenic's intention was: the purpose of custom elements is to do similar kinds of things to existing HTML elements, with the same genera kinds of interfaces exposed. It's not to let them express things in whole new ways. For example, a feature to define an element where the open tag uses square brackets instead of angle brackets would probably not be a valuable addition to custom elements. It might be that, in some cases, we need to go beyond the way existing HTML elements have done things to enable specific other kinds of elements. But that has to be actually demonstrated, not just assumed. And it ought to be a real need, not just a gratuitous difference from how existing elements do things. |
CSS uses function-like syntax in a number of places that are not functions in the programming language sense of the term and do no evaluation. It's just syntax. Please stop conflating the two concepts.
Custom elements are by definition "hypothetical use cases". They are an extension point for authors to invent new elements that we haven't thought of yet. Why restrict an extension point to only what's already been done, or worse, a subset? There are also existence proofs of pseudo-classes that reflect state that use functional syntax, namely And the "complexity" we're talking about here is simply giving custom element authors access to something CSS can already do, namely pseudo-classes with functional syntax and more than a simple boolean flag. There's no new CSS syntax. This isn't inventing something new, it's giving custom elements the ability to do something HTML elements already can. There have been numerous proposals for pseudo-classes that use functional syntax that aren't selector math. This is also part of turning "custom state pseudo classes" into simply "custom pseudo classes" (along with the syntax change). Let authors decide what they want to use them for, and allow them to mint new pseudo-classes, just like HTML elements can. |
Perhaps you share more context with Domenic than I do. My interpretation of what he wrote was based on how I understood the words he wrote. Nothing more, nothing less. Tab's explanation of what Domenic was likely going for makes sense to me, and I very much agree with those goals. Let me be clear and blunt. I am not arguing for the sake of argument. I am not deliberately misrepresenting anything anyone says. I'm also not trying to "win". I may not take everything written in the exact sense in which it was meant, but all I can offer is my best effort trying to understand the sense that was conveyed. As does everyone else. Human communication is not perfect. I am acting in good faith trying to improve the web platform. And I presume you all are too. It's clear to me that several of you have differing viewpoints than I, and others, do. I am making best efforts to try to understand your viewpoints and take your concerns into consideration. Please do the same for me. Talking past each other is frustrating.
Giving an author access to a custom pseudo-element isn't a "whole new way" of expressing things. It's giving custom elements the exact same capability that HTML elements already have. That's a goal, right? |
No need for hyperbolic examples here. Quoting myself from a few comments back:
Swapping the bracket characters used by tags is not a useful characterization of what's being talked about here; that would be a completely novel functionality that doesn't exist anywhere in HTML, and without a strong justification, wouldn't be appropriate for custom elements. What we're talking about here is whether or not custom pseudo-classes should be permanently restricted to a subset of pseudo-class syntax, or should (eventually) be allowed to use the full syntax that existing pseudo-classes use. So far, I haven't seen good arguments for ruling out the possibility of custom functional pseudo-classes. The attempted arguments have been that (a) CSS only uses functional pseudo-classes to express "tree information" or combinator-ish things, not internal states of an element, and (b) there are no reasonable examples of internal states that would be better exposed as functional pseudo-classes rather than a set of boolean pseudo-classes. Neither of these are correct. In the current Selectors spec, most of the functional pseudo-classes are combinator-ish (
Even if you want to push the point that an element's language comes from the tree rather than being an internal state, you cannot argue that the design of So, concretely: @othermaciej, are you trying to argue that it is unrealistic that a custom element will ever want to do something remotely similar, where it wants to let authors match over a large (or infinite) set of states, so we shouldn't try to design an API that eventually accommodates it? I'm trying to get this argument to focus on the concrete questions rather than continuing to circle around abstract disagreements. Note that I'm skipping over the multiple examples of functional pseudoclasses that have been proposed that are definitely based on internal state, which I linked to and talked about in previous comments; this response is too long already.
I strongly agree, but that's completely tangential to the question at hand, which is whether custom pseudo-classes will ever want to do use the full set of syntax that existing pseudo-classes do. Nothing being discussed here has suggested going beyond current CSS syntax in any way. |
This spec is not "custom pseudo-classes", it's "custom state pseudo-class" in particular. So we don't necessarily need to expose every possible face of CSS pseudo-element syntax. Just enough to express states. Current HTML elements often express state as a styling hook. This is generally specific to one element or a subset of elements. Mostly they are documented here and they represent a specific state of the element. https://html.spec.whatwg.org/#pseudo-classes It's really easy to think of examples of states that aren't one of the built-in ones which might apply to novel custom elements. For example, a All I'm asking for is a plausible example of element-specific state like the above which would clearly benefit from the functional syntax, to the point that a fixed set of values wouldn't do the job. In particular, I don't think Also, an argument along the lines of "who knows what custom elements could do, they could do anything" is not, itself, a suitable example. Also, the only examples I see in previous comments are how existing state-like pseudo-classes could be reworked to use functional syntax, but they do not explain why it would be necessary or helpful to do so. (It seems seems self-evidently not necessary). If no one can present such an example, then I think we can presume there's no obvious use case. So far, the only real argument presented is syntax completionism, and I don't think that's a good enough reason to add complexity to this particular API. |
Because I don't think non-boolean state support is mandatory, the first version of the feature and its implementations won't have non-boolean state support, and it's possible that we never add non-boolean state support. I'd propose the first version as:
A future version might have non-boolean states. Non-boolean states will be supported by a different selector syntax and a different IDL attribute.
Any objections? |
I wonder how well worked out setlike/maplike are. In existing collection classes, e.g., |
I don't object to the first part of your proposal (for the first version). While I still feel that non-boolean states are useful, as I've said multiple times, I'm OK with version 1 being boolean only, so long as there's a reasonable path to go beyond that. I can live with a setlike API, however I still prefer a maplike, even for V1. A maplike can still have an additional If we start with a setlike, we can still add I do object to your plans for a future version for several reasons.
|
According to the current definition of |
I still think non-boolean states is unnecessary. Probably we won't implement it in Google Chrome unless other browser vendors strongly support it. |
* Make 'states' attribute a setlike<DOMString>, not a DOMTokenList See #4 (comment)
See https://wicg.github.io/custom-state-pseudo-class/#ex-non-boolean-state
If the feature needs to support non-boolean states, probably
ElementInternals
should havestringStates
IDL attribute_internals.stringStates.add("readyState", "complete");
:state(readyState=complete)
The text was updated successfully, but these errors were encountered: