open-ui
open-ui copied to clipboard
Consider "toggle" (e.g., show/hide - expand/collapse) button or attribute
With the evolution of popover, developers got the ability to use a button to toggle the displaying of a popover element in the top layer without the need for JavaScript.
What HTML is still lacking though is a way to use a button to toggle the display of elements that don't get rendered in the top layer. The best way to do that now is to use a standard button element with an aria-expanded set to true/false. In the grand scheme of things, the JS needed for this is rather trivial... but the fact that any JS and ARIA are needed means that people will try to work around those requirements, or have the potential to implement them incorrectly.
Now yes, we have the details and summary elements to make native disclosure widgets - but these have some oddities, to put it politely, and there is no room for leniency with their placement in the DOM. The triggering summary element MUST be a child of the details, which awkwardness of the current elements aside, this required parent/child relationship can be a deal breaker for consideration. E.g., a button to toggle a hidden navigation appears as the first element in a header, but the revealed navigation is positioned after the header in the DOM. Even if details/summary had no other issues with it, the mentioned layout would make their use a no-go.
And just because I don't think I could make this issue without mentioning it, yes, there's also the CSS toggles proposal. I would expect some learning / ideas from that to be relevant here. Though I would submit what I'm proposing here is much smaller in scope, with far less "let the browser figure out what sort of toggle this is and provide the correct keyboard behaviors and hope to god that developers didn't muck something up that we didn't consider". And more just "let's make a button show/hide a specified target element, and expose an expanded/collapsed state for the button while we're doing it" which is exactly what we have with buttons that toggle popovers... just again, minus the top layer part, please.
I support this idea!
The comparison with details/summary is helpful, and it makes sense to want something without its oddities (like DOM placement).
In terms of accessibility API, is the only thing it would do manage expanded/collapsed state? Would it also convey some kind of aria-controls relationship (even if zero AT seem to expose that relationship in any way?)?
A semantically neutral component would introduce many hardels in this particular case. We may be better off with a proposal for a hamburger menu in which the intent of use and the expected keyboard functionality would be much more intuitive. Neil Osman Accessibility engineer @ accessibility team
On Mon, Apr 3, 2023 at 9:58 PM Hidde de Vries @.***> wrote:
I support this idea!
The comparison with details/summary is helpful, and it makes sense to want something without its oddities (like DOM placement).
In terms of accessibility API, is the only thing it would do manage expanded/collapsed state? Would it also convey some kind of aria-controls relationship (even if zero AT seem to expose that relationship in any way? https://a11ysupport.io/tests/tech__aria__aria-controls)?
— Reply to this email directly, view it on GitHub https://github.com/openui/open-ui/issues/700#issuecomment-1494819585, or unsubscribe https://github.com/notifications/unsubscribe-auth/AMBTHVY32XPR4RMOPGSXKULW7MMT3ANCNFSM6AAAAAAWL5LZFA . You are receiving this because you are subscribed to this thread.Message ID: @.***>
@hidde likely not aria-controls, but similar to how popovertarget is shaping up to work, which has an aria-details relationship.
@NeilWix I think you misunderstood the proposal, as there was no mention of adding a semantically neutral component, and as the proposal was actually for either extending button element behaviors, or adding a new type of button, your mention of the intuitiveness of keyboard behavior is puzzling.
Is this also related to https://github.com/openui/open-ui/issues/333 ? Just linking it up so we can keep track of them and hopefully close things as they get irrelevant, or look back and see what we said in the past.
@bkardell anything that is proposed for showing/hiding content will always be related to each other :)
but outside of that, no. this is not a tabs or menu or treeview proposal. this is just for adding expand/collapse capabilities and programmatic state to buttons - e.g., what has already been done with popovertarget, but without promoting the target to the toplayer.
Could really be beneficial to have something like this.
A side question i have about this, is that if would beneficial to have this state exposed to CSS as well? Reason for this is that; for example, when I style collapsed items with aria-expanded I tend to use this attribute in CSS as well
button[aria-expanded="true"] {
/* rotate the icon or something like that */
}
Why I do this, is to prevent people forgetting it... "forgot aria, you don't get the styling".
In the popover case, it could also be used to give the button a certain visual state based on that. Although less important because (If I'm interpreting your suggestion correctly) it would be automated "behind the scenes, without JS". Still, I thought I might mention this side question.
+1 for the idea in general
I don't know how often I'd need this in a future world where more stuff from this group has shipped but I can say I have probably implemented various toggle buttons more than anything else, as they are very often a necessary piece of anything larger I need. It would certainly be nice to have one that just works and handles all the appropriate aria natively. Even if it becomes useful over time as more powerful things get built into the platform I imagine it would still come up.
well, all the appropriate aria (accessibility mappings) in this case would be purposefully limited to more straight forward disclosure widgets (largely just exposing an expanded/collapsed state for the button. providing other meaningful semantics - details relationship - when the invoked content is not next to its invoking button in the DOM).
other potential components that could come from this group, e.g., making a standardized proposal for tabs, menus, treeitems, etc. those would - at their core - still show/hide content, but they'd communicate very different semantics and have different keyboard functionalities.
so, hence this proposal. start with the most basic / common component needed to show/hide content. and then create other components that are suited for their task thereafter.
I would love for the feature to exist, with aria-expanded under the hood, and I think it would solve a lot of the use cases we want toggles for without added scripting.
Could we leverage something like CSS container queries (state queries) for this, i.e. is-toggled to style it?
@una i think that's an implementation detail i'd really like to hear more about from what has been investigated with CSS toggles, as I personally don't see any reason why not, so long as whatever the current visible state of the associated content (hidden or not) could be communicated back to the button element, so that it could correctly expose the expanded/collapsed state.
maybe we can discuss this more in next week's call, especially if david ends up being able to provide an update on the state/fate of css toggles.
One thing that's not clear to me (and might differ depending on the details of this proposal, what hooks into CSS and JS it eventually has, etc.) is how easy it would be to mis-use what this is proposing to build components (for example, tabs) for which it would have the wrong accessibility semantics. In other words, depending on details, this might end up being a primitive that developers would want to use for a big portion of the things that toggle could be used for -- and if that's the case, that might run into cases where the accessibility roles and keyboard handling are wrong.
Or, to put it another way, it seems in some ways like a much lighter weight version of CSS toggles (again, perhaps depending on what the CSS and JS integration looks like)... and might end up sharing both some of the advantages and some of the disadvantages.
What if the natural way to think about this is backwards and there needs to be an attribute like popover but for the sections that expands/collapses and a button with an expandstarget gets aria-expanded based on the target's state?
So something like
<button expandstarget=it>toggle</button>
<div id=it expands open>
this is open until the button gets clicked
</div>
A closed [expands] element should open when the button is pressed, search in page finds a match (with a way to opt out), and the location.hash matches the id (with a way to opt out). When closed it should be inert and the default styles would be like [hidden] so you could easily override them to do something fancier.
The downside of that specific outline is there's no way to force it open in a container size query unless you can set inert in CSS (which I was 👍 on anyway). It would work for @media (print) though since it doesn't matter if that's inert, I suppose
If we go on the basis that this would utiltise the invokerbutton proposals. I guess the question is what would the action be and would we need any additional attributes to define the expandability?
Or does the ability to invoke the details externally effectively solve this?
to be honest, when i logged this issue/idea, the intent wasn't really that people would use this with details - that already exists and i struggle to see the value in having a control to toggle a details separate from a details - since there's already a summary element either manually added or automatically generated as the first child of the details to do that.
a details element by itself has no meaningful semantics exposed to AT that isn't reliant on the summary element, or extra effort to expose such semantics by a developer (nor should it, lest that be considered a bug). And i mention this (at a high level, i'm leaving out some details - ha) simply to the point that if someone were going to create a button that could toggle a div/article/fieldset/list/whatever, then there's no reason to even need to get details involved and wrangle with changing its current behavior/potential legacy browser issues with any sort of polyfill.
There hasn't been any discussion on this issue for a while, so we're marking it as stale. If you choose to kick off the discussion again, we'll remove the 'stale' label.
We still dig this idea, it's not stale <3
Echoing some of the earlier comments but with the added foresight of invokers, I think this could be handled with a new attribute like disclosure. Example:
<button invoketarget="more">Show more</button>
<div disclosure id="more">… (more stuff here) …</div>
Similar to popover, this would toggle the visibility, and implicitly set aria-expanded and whatever else is necessary.
I specifically like how low-level it is and how little "API" there is, which makes it easy to use for simple cases while still being flexible enough to support more complex ones. Big improvement over <details> and/or JS-driven disclosures imo.
There hasn't been any discussion on this issue for a while, so we're marking it as stale. If you choose to kick off the discussion again, we'll remove the 'stale' label.
I really like this, but I'm curious how this would work under the hood.
Let's say the API is like what @mayank99 is proposing with a disclosure attribute. Would it simply change the CSS display attribute?
What if we wanted our disclosure element to be display: grid, for example? When the element is toggled to be visible, would the user agent set display: block?
@JoshTumath I think the power of this API is in the implicit toggle whose state is maintained by the user agent.
- The user agent doesn't really need to set
display: block, but should definitely setdisplay: noneduring the closed state. - For overriding the display, an
:openor:disclosure-openselector would be sufficient (similar to:popover-open).
- The user agent doesn't really need to set
display: block, but should definitely setdisplay: noneduring the closed state.
Maybe instead of display: none it would be better to be like hidden=until-found and use content-visibility: hidden?
I agree that using the content-visibility: hidden and hidden until-found mechanism (probably implicitly like details does) is probably better than toggling display.
I guess it does beg the question is there a use case where you don't want the contents to be searchable (aka the old details behaviour)? If so we could make the new attribute be an enum so it can be configured.
I know tabs are one case where you sometimes don't want it to be searchable. But I would rather we address that specific case separately with dedicated tab elements.
If this is meant to be a low-level disclosure primitive, then it shouldn't mess with the searchability.
Today, the contents of <details> being exposed to find-in-page (in certain browsers) greatly limits the usefulness of the element. It's handy for a certain type of use-case (e.g. an FAQ page), but is largely undesirable when building complex dynamic applications, where disclosures are used throughout the interface to reduce visual clutter. When the end user searches for something on the page, I don't want them to unintentionally open random disclosures all over the place.
That's not to say it should not be possible; it should just be explicit (rather than implicit like in <details>). Maybe the new disclosure attribute could be combined with hidden=until-found? This would allow for both behaviors, while avoiding any surprises.
<button commandfor="more">Show more</button>
<div id="more" disclosure hidden="until-found">… (more stuff here) …</div>
Side note: content-visibility: hidden does not preserve searchability (The web.dev article might be misleading on this topic). Afaict, the hidden=until-found behavior is unique to the attribute and does not have a proper CSS equivalent.
IMO, i'd much rather someone opt into hidden until found than have that be the default.
sub-navigations, custom menus, sidebars / toggle tips that are meant to only be toggled via a button - there's a lot of content in many websites / complex web apps beyond just tab widgets that would be silly to find their content if doing a find in page. i'd submit there's probably more of these in a page than one realizes, which would make it rather annoying to have to undo a default hidden until found for so many items.
that said, i can see the use case for wanting to pair this with hidden=until-found, so that sounds reasonable to allow that attribute/state to take precedent over, what i'd prefer, a default display none
and regarding content-visibility: hidden - definitely don't want that. i've had to deal with devs using that lately and making their apps incredibly difficult for people to navigate with a screen reader.
I think I mostly agree, though if I were to play devil's advocate for a moment.
Today, the contents of
<details>being exposed to find-in-page (in certain browsers) greatly limits the usefulness of the element.
There are other more problematic issues limiting <details> usage/adoption, @scottaohara touched on them when he initially opened this issue and detailed them further in his great blog post.
It's handy for a certain type of use-case (e.g. an FAQ page), but is largely undesirable when building complex dynamic applications, where disclosures are used throughout the interface to reduce visual clutter.
When the end user searches for something on the page, I don't want them to unintentionally open random disclosures all over the place.
sub-navigations, custom menus, sidebars / toggle tips that are meant to only be toggled via a button - there's a lot of content in many websites / complex web apps beyond just tab widgets that would be silly to find their content if doing a find in page.
I don't think these are the best examples to base our reasoning/decision making on. As someone with AuDHD and Dyslexia[^1] find-in-page is very important for me to be able to navigate web pages[^2], without it I have to read everything which leaves me overloaded, overwhelmed, and running low on spoons.
Sub-navigations, custom menus, sidebars / toggle tips, random disclosures, and other parts of dynamic applications are actually perfect examples of why I struggle so much when relying on find-in-page currently. These are situations where I really want find-in-page to work so I don't have to manually open every little disclosure.
[^1]: I mention these three as I feel they're the most pertinent, though there are others that are pertinent I don't want to over complicate things.
[^2]: I'd recommend checking out 4.3.6 Provide Search (Pattern) from Making Content Usable for People with Cognitive and Learning Disabilities to learn more.
That's not to say it should not be possible; it should just be explicit (rather than implicit like in
<details>).
IMO, i'd much rather someone opt into hidden until found than have that be the default.
I think making it an option to enable or disable find-in-page and fragment navigation is a great idea. I think the more accessible/usable option should be the default. In my mind than means it should be enabled by default but I'd like to hear other arguments.
Side note:
content-visibility: hiddendoes not preserve searchability (The web.dev article might be misleading on this topic). Afaict, thehidden=until-foundbehavior is unique to the attribute and does not have a proper CSS equivalent.
and regarding
content-visibility: hidden- definitely don't want that. i've had to deal with devs using that lately and making their apps incredibly difficult for people to navigate with a screen reader.
Yikes! I think I got confused because a lot of the documentation[^3] about hidden=until-found[^4] it mentions the fact that content-visibility: hidden is used instead of display: none right along side talking about find-in-page and fragment navigation working, which makes it seem like that is what provides/enables the functionality. Thanks for catching my mistake!
[^3]: "The hidden until found state" section in the MDN article, the "The hidden attribute" section in the HTML spec, and—as was already mentioned—the "Caveats" section in the web.dev article
[^4]: and probably <details> too.
Yikes! I think I got confused because a lot of the documentation3 about hidden=until-found4 it mentions the fact that content-visibility: hidden is used instead of display: none right along side talking about find-in-page and fragment navigation working, which makes it seem like that is what provides/enables the functionality. Thanks for catching my mistake!
Fwiw you weren't wrong content-visibility is the CSS property that enables hidden until-found. I think Scott is basically just saying we need to be careful and only use that where it makes sense (such as how details does now).
I'm happy to defer to others on whether we want contents to be searchable by default. I like you generally prefer things to expand when searched, but I can absolutely see that there's use cases where it's not desirable. On that basis provided there's a way to cater to both cases I'm happy.
Adding to agenda to discuss in more detail and try and get the ball rolling because this feels like a useful addition and something we should be able to gain consensus on. Especially because there's clearly use cases that aren't overlapped with details.
Some questions to think about:
-
(Discussion above) should find in page work when closed.
-
Would this new attribute enforce / require a specific set of aria roles. Popover for example enforces a minimum of group. I'm guessing this new 'bruce' attribute probably shouldn't prescribe a specific role (beyond perhaps a minimum) because of the wide variety of use cases.
-
Obviously this can (and will) be bikesheded to oblivion, but what name for the attribute? I'd like something such as expand or expandable. Disclosure feels too specific about a single use case to me.
-
What should the commands for this be? (Again bikeshedding I know) expand, collapse and toggle-expansion?
4a. What should the equivalent JS APIs be called?
-
Should this match the :open pseudo class or should it be something else?
-
Are there any elements where this attribute shouldn't be valid? (E.g. details seems a candidate and maybe dialog?)
-
Do we need to handle an initially open state? If so how?
i'm going to walk back a couple of my concerns with the find in page, since the things i'd be most concerned being exposed by find in page are UI elements which should be built using popover, and likely not this feature. so popup menus, tooltips / other popups that would clutter the UI / potentially block what people were searching for, and which wouldn't make sense to find for those who purposefully didn't want to find out more information about something they weren't searching for wouldn't be impacted.
so i'm less concerned about it being a potential default - though i think it really should be a user setting in the end. it absolutely can be helpful for some, and incredibly annoying if it just clutters the find in page functionality for others.
using this page as an example, the context menus that go along with each comment have an item for "report content" in each. There are about 27 comments in this thread now. Also, we've been talking about "content", and that word has been used 24 times in comments. So, in the hypothetical situation where github revised their menu popups to use this proposed feature, rather than popover - and the feature defaulted to hidden until-found, searching for the word "content" would get about 61 hits, and about half those hits would be repeat "report content" menu items.
anyway...
to some of luke's questions (no opinions on naming at this time because i hate that game)
(Discussion above) should find in page work when closed.
maybe! some people will want it, others won't. it'd be best to support both somehow.
Would this new attribute enforce / require a specific set of aria roles.
IMO, probably similar.
Should this match the :open pseudo class or should it be something else?
i'd hate to not be consistent, so i'd tentatively say :open instead of ":open-but-named-something-else"
Are there any elements where this attribute shouldn't be valid? (E.g. details seems a candidate and maybe dialog?)
we don't want yet another way to open non-modal dialogs? ;)
no but seriously - popover is a global attribute, imo, not because it actually makes sense to use on all elements, most global attributes don't make sense to use on all elements... i could see this falling into a similar space. does this proposed attribute belong on a dialog, meta, html, b or style element? no more so than tabindex or title or draggable...
Do we need to handle an initially open state? If so how?
yeah, i'd think so, since people can use open now with details - and can setup their custom disclosure widgets to have a class, or use an aria-expanded=false + .my-whatever { display: none } ruleset and thus anything set to aria-expanded=true would have a default open state.
I don't know whether find in page should be opt in or opt out but it should be an option, like bikeshed vs. bikeshed=whichever-is-not-the-default.
:+1: for supporting open, matching :open, supporting the toggle event, and anything else that makes sense to copy. Don't see a reason to not default to being consistent here. There should not be a lot of new things to learn here. There's good precedent to lean on.