focus-visible icon indicating copy to clipboard operation
focus-visible copied to clipboard

Handling `:focus-within` equivalent.

Open plinehan opened this issue 6 years ago • 44 comments

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.

plinehan avatar Jun 19 '18 18:06 plinehan

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!

robdodson avatar Jun 19 '18 19:06 robdodson

Agreed, this is a great question.

What is the use case which motivated you to make this change in your fork of the script?

alice avatar Jun 27 '18 00:06 alice

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 :)

plinehan avatar Jun 27 '18 17:06 plinehan

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.

alice avatar Jun 27 '18 21:06 alice

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.)

OliverJAsh avatar Nov 08 '18 15:11 OliverJAsh

I think :has(:focus)/:has(:focus-visible) are better than :focus-within/:focus-visible-within. Maybe :has is too big a thing to proceed?

Justineo avatar Nov 08 '18 16:11 Justineo

@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 avatar Dec 05 '19 11:12 MarcoZehe

@MarcoZehe is there a demo we could play with? I'm having a hard time understanding the use case.

robdodson avatar Dec 19 '19 21:12 robdodson

@OliverJAsh sorry for the lag. Can you show me what your markup looked like?

robdodson avatar Dec 19 '19 21:12 robdodson

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.

MarcoZehe avatar Dec 20 '19 05:12 MarcoZehe

@robdodson https://jsbin.com/fokexoc/1/edit?html,css,output

OliverJAsh avatar Dec 20 '19 12:12 OliverJAsh

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...

robdodson avatar Jan 10 '20 18:01 robdodson

@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?

robdodson avatar Jan 14 '20 00:01 robdodson

@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?

robdodson avatar Jan 14 '20 00:01 robdodson

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.

t3chguy avatar Jan 14 '20 07:01 t3chguy

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

OliverJAsh avatar Jan 14 '20 11:01 OliverJAsh

@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.

robdodson avatar Jan 27 '20 20:01 robdodson

they are custom components using tabindex but I don't think the proposed fix would solve my issue without testing

t3chguy avatar Jan 30 '20 17:01 t3chguy

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?

robdodson avatar Jan 30 '20 23:01 robdodson

I have a scenario where :focus-visible-within would come in very handy: https://codepen.io/Miragecraft/pen/mdrRLXw

miragecraft avatar Dec 14 '20 00:12 miragecraft

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.

bkardell avatar Dec 14 '20 02:12 bkardell

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.

miragecraft avatar Dec 14 '20 07:12 miragecraft

+1 for focus-visible-within. If I can give my use-case:

image

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)

unilynx avatar Feb 26 '21 16:02 unilynx

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.

bathos avatar May 12 '21 07:05 bathos

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?

robdodson avatar May 24 '21 19:05 robdodson

A good news: folks from Igalia is working on implementing :has for Chromium.

https://bugs.chromium.org/p/chromium/issues/detail?id=669058#c17

Justineo avatar Jun 03 '21 11:06 Justineo

Does anyone know if any progress have been made here?

lgenzelis avatar Feb 08 '22 02:02 lgenzelis

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".

bathos avatar Feb 08 '22 04:02 bathos

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

danbrellis avatar Mar 18 '22 19:03 danbrellis

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.

craigkovatch avatar Mar 23 '22 00:03 craigkovatch