focus-visible
focus-visible copied to clipboard
Handling `:focus-within` equivalent.
Is there any plan to handle the equivalent of :focus-within
for the :focus-visible
pseudo-selector in the CSS spec? Something like :focus-visible-within
?
I modified [my version of] the script to add the focus-visible
class to the body whenever focus is visible. Then I can write a selector like body.focus-visible foo:focus-within
to style foo
when focus is visible within it, but I don't see an obvious way to do that in pure CSS once the spec is updated.
That is a great question, and yeah, I don't know how you would do this without something like :focus-visible-within
. I'll add this as a note for @alice and I to discuss when she gets back from vacation. Thanks for filing it!
Agreed, this is a great question.
What is the use case which motivated you to make this change in your fork of the script?
They are almost all cases where we have an input and a set of associated buttons (e.g. a search input box and a "search" button) and we'd like the focus to be around the outer container. I think in most of these we could just use focus-within
since the input is always focus visible, but I can imagine cases it would be nice to detect if the search button was visibly focused or not.
We have a few other cases where it just works out conveniently to use focus-within due to how to DOM happens to be constructed. We're retrofitting correct indicators into an extant codebase, so it is handy to have this kind of power :)
Good use case, thanks!
This is annoyingly making me think about modality again, like the original idea @bkardell had... it seems wacky to have :focus
, :focus-within
, :focus-visible
and :focus-visible-within
.
Will keep thinking about it.
We also just ran into this. I have a hidden input inside a label, which I apply focus styles using :focus-within
. When the label (and thereby input) is actioned via mouse users, we end up showing focus styles. (Unfortunately the team decided to blur the input immediately after use to avoid this.)
I think :has(:focus)
/:has(:focus-visible)
are better than :focus-within
/:focus-visible-within
. Maybe :has
is too big a thing to proceed?
@t3chguy and I are currently beating around something like this in the Riot web client. A toolbar only shows if the mouse hovers over the relevant message. We are at a point where the action toolbar shows up if screen readers or keyboard users move into the actual message tile, but the way CSS is set up right now, with the .focus-visible polyfill, the toolbar disappears once the screen reader moves focus to a button inside the toolbar. Even though that is within the toolbar and on an actionable button. So having this would be really awesome, since we can't seem to convince the powers that be to always show the toolbar for each message in the chat.
@MarcoZehe is there a demo we could play with? I'm having a hard time understanding the use case.
@OliverJAsh sorry for the lag. Can you show me what your markup looked like?
The use case is Riot Chat that shows an action bar for each message when hovering over it. However, there are a few situations where this doesn't work reliably, for example for screen readers, we adjusted this to also be :focus-within, but that doesn't fire in all situations. We need to do this so screen reader and keyboard users (once full keyboard access is implemented) have access to all controls no matter where within each message container the focus happens to be.
@robdodson https://jsbin.com/fokexoc/1/edit?html,css,output
hm yeah both of these make sense. It looks like the TAG folks added a CSS selectors level 5 label to the prior discussion here: https://github.com/w3c/csswg-drafts/issues/3080#issuecomment-437048758
I wonder if they're thinking of exploring the :focus()
or :has()
option...
@MarcoZehe That makes sense. You're basically replacing hover with focus-visible for folks using assistive tech, but that means that if the hover card contains something focusable you want to keep it from closing when the user tabs to that focusable child inside of the card.
Since you mentioned that the user is moving focus inside of the toolbar, could you use focus-within on the toolbar itself to keep it from disappearing?
@OliverJAsh yeah that's a tricky example... It feels like the issue is really with <input type="file">
and the fact that you have to use the label hack to make it styleable. In other words, if you could just style the <input type="file">
button you wouldn't need :focus-visible-within
, correct?
Since you mentioned that the user is moving focus inside of the toolbar, could you use focus-within on the toolbar itself to keep it from disappearing?
Not quite because then clicking on a toolbar item would mean the toolbar stays open (even after hover is removed), which is undesirable in this case.
In other words, if you could just style the
<input type="file">
button you wouldn't need:focus-visible-within
, correct?
@robdodson Correct! Although consider this example where we don't want to hide the input
: we want to give the label
:focus-visible
styles when the input
within has focus https://jsbin.com/wexehirubu/1/edit?html,css,output
@t3chguy
Not quite because then clicking on a toolbar item would mean the toolbar stays open (even after hover is removed), which is undesirable in this case.
Is that because toolbar items are custom components using tabindex? I think a <button>
, for instance, won't retain focus in Safari or Firefox, but will in Chrome. I'm mostly asking because if <button>
didn't retain focus, I'm curious if it would fix your issue.
they are custom components using tabindex but I don't think the proposed fix would solve my issue without testing
ah yeah. I believe all browsers retain focus when you click on something with tabindex.
Do you want the toolbar to close when someone using a keyboard clicks on the item? Because I think it would still be matching :focus-visible-within at that point. If the button already has focus and you hit spacebar, I don't think it blurs focus.
So I think the only way to work around that would be to programmatically move focus out of the toolbar. Which makes me wonder if :focus-visible-within would actually be useful in this scenario?
I have a scenario where :focus-visible-within
would come in very handy: https://codepen.io/Miragecraft/pen/mdrRLXw
Yeah, we've discussed this and a lot of other things like it in csswg. We know we should do something here, it's just not clear what. :has could, in theory solve a lot of things but in practice it is unclear it is implentable. Alternatively, a hundred withins would create their own problems. Sorry I know that's not a real helpful reply. Just wanted to say those are the challenges.
By "a hundred withins" I assume you are referring to other pseudo-classes. I really don't feel just by adding :focus-visible-within
it suddenly means every other pseudo-class needs a -within
variant too, and for consistency sake it makes more sense to have a -within
variant to :focus-visible
to align with :focus
and :focus-within
than not having one.
In addition, I feel that :focus
and :focus-visible
benefits the most from having the -within
variant due to them being critical for accessibility, so adding this one variant gives the greatest return on investment.
+1 for focus-visible-within. If I can give my use-case:
This is a <details><summary>
... and the blue focus border is around the summary. giving how it cuts through the element, we'll probably switch to focus-visible for this. but ideally i would highlight the entire 'details' element (focus-within) but only when needed (thus... focus-within-visible)
I agree with @miragecraft — this slope doesn’t seem very slippery? I understand that it seems to cry out for generalization, but the need for :focus-visible-within is pressing in a more we-feel-it-every-day way than other possible functionality that generalized “within” selectors might unlock — and correct me if I’m wrong, but I’d guess that it doesn’t present the same performance challenges as a generalized within selector?
This may sound silly, but :focus-visible has been life-changing. We no longer have to dread the we’ll-just-ask-the-new-intern-to-disable-these-focus-rings-if-you’re-gonna-be-so-annoying-about-it workaround. But the matrix is incomplete — without :focus-visible-within, there’s still a subset of cases (which seem pretty random to non-developers) where we have to say “no” to the inaccessibility overlords. In the end, that “no” doesn’t always work even if you stand your ground.
To put it another way, the absence of :focus-visible-within, like :focus-visible before it, has consequences on the net accessibility of the web. The reasons for that are embarrassing, but it’s still what often happens. This seems more important than whether the selector is maximally DRY.
I think there's still some discussion around adding it to :has()
in the csswg, https://github.com/w3c/csswg-drafts/issues/3080#issuecomment-839559449
In my opinion this may be the best option?
A good news: folks from Igalia is working on implementing :has
for Chromium.
https://bugs.chromium.org/p/chromium/issues/detail?id=669058#c17
Does anyone know if any progress have been made here?
yes!! :has is real, sorta! nobody's shipped it on a main channel yet, but Safari TP has it and Chromium work seems to be ongoing/active (there are related commits from this week it looks like). I'm not how to interpret FF's fourteen(!)-year-old issue though. There are associated issues that look active, but it isn't clear to me whether they're directly related or just "other stuff in selectors 4".
An additional use case is having a checkbox wrapped by the label where you are styling the label and 'hiding' the checkbox:
<label><input type="checkbox" />Label</label>
label {
background: blue;
color: #fff;
display: inline-block;
}
input {
appearance: none;
}
When tabbing, the focus is set to the checkbox, so if you want to style the label, you need to use focus-within.
label:focus-visible, label:focus-within {
outline: 2px solid #21578A;
}
label:focus:not(:focus-visible){
outline: none;
}
The above css still shows the outline around the label when tabbing.
EDIT sorry, just realized this is the same use case as brought up by @OliverJAsh
We have a use case for this as well, which I think is a fairly common hack, to show custom focus indicators on checkbox/radio elements using ::before
(or ::after
, whatever) pseudos. My current focus rule looks like &.focus-within.focus-visible::before
. These can't be translated directly to the newly-available (yay!) :focus-visible
pseudo because it doesn't match in the way that I don't need to explain since that's the whole reason for this Issue :D
Long-winded way of saying +1, but another I-think-common way of needing it.