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

Do we need :focus-visible-within ? #3080

Open
dbaron opened this issue Sep 4, 2018 · 26 comments
Open

Do we need :focus-visible-within ? #3080

dbaron opened this issue Sep 4, 2018 · 26 comments
Labels

Comments

@dbaron
Copy link
Member

dbaron commented Sep 4, 2018

While looking to close out w3ctag/design-reviews#233, one other thought occurred to me:

Is there a need for :focus-visible-within to complement :focus, :focus-within, and :focus-visible?

In particular, because of limitations on CSS selectors (that is, the difficulty of selecting an element that is an ancestor of an element with a particular characteristic), we've added :focus-within to have a version of focus that behaves like the hierarchical :hover and :active. I think this was desirable because it's not unusual for a visible container to be styled differently when something inside it has focus. Consider examples ranging from an operating system window to a <fieldset> with a bunch of form controls in it. (I suspect there may be better documentation if you trace from where we agreed to add :focus-within.)

It's not clear to me whether the use cases for :focus-within and the use cases for :focus-visible combine. Do we also need :focus-visible-within, or not?

/cc @alice @robdodson @bkardell @AmeliaBR @frivoal

@dbaron dbaron added the selectors-4 Current Work label Sep 4, 2018
@AmeliaBR
Copy link
Contributor

AmeliaBR commented Sep 4, 2018

I personally don't see a use case.

:focus-within is for cases where you really want to enhance focus styling (highlight/expand an entire group of interactive elements), :focus-visible is for cases when you want the styling to be more subtle, only-when-necessary.

But regardless, there's nothing stopping it from being added later if there is a strong demand from authors, once those authors have a chance to really work with the two new selectors.

@Malvoz
Copy link
Contributor

Malvoz commented Sep 6, 2018

This was brought up in WICG/focus-visible#151

@tabatkins
Copy link
Member

I don't think there's any significant use-case difference between "want to see if a descendant has :focus" and "want to see if a descendant has :focus-visible". If you want one, there's a good chance you might want the other. (Or to put it another way, :focus is often not what you actually want in the first place; you usually want :focus-visible, and thus you'll probably want a -within variant if you're currently suboptimally using :focus-within.)

However, if we do decide to add such a thing, I'm against just spamming more keywords into the name; that's unwieldy and you have to remember the (arbitrary) order of the modifier keywords. Instead, I'd say we should expand :focus into a :focus() functional pseudo, like :drop(), taking a list of keywords in any order. So you'd write :focus(visible within) or whatever.

@Justineo
Copy link
Member

Justineo commented Nov 8, 2018

IMO it's better to have :has(:focus)/:has(:focus-visible) instead of :focus-within/:focus-visible-within. Not sure if this is discussed earlier.

@Justineo
Copy link
Member

Justineo commented May 12, 2021

Is there any chance that we support the :has(...) syntax but temporarily restrict the usage within :focus and :focus-visible? That would introduce little performance overhead and provide some degree of extensibility.

An example is when :not() is first introduced, only simple selectors are allowed as its argument and in Selectors Level 4 we extended that to some non-simple selectors.

@craigkovatch
Copy link

craigkovatch commented Mar 23, 2022

Just want to pile on here to say: there are definitely use cases for this, and I also like Tab's idea of :focus(within whatever), assuming that ship hasn't sailed too far :D WICG/focus-visible#151 (comment)

@bkardell
Copy link
Contributor

Since I see some comment here, it's worth noting that :has is in development :has() in 2 engines (chrome 101+/supporting things based on that chromium build under experimental web platform features and webkit with TP versions like Safari in the most recent). In both cases, at least currently

.thing:has(:focus-visible) { .... }

works just fine, so if that ultimately lands it will address this issue (as well as several others, we should probably review)

@craigkovatch
Copy link

@bkardell I've no objection to that, although :focus(within whatever) wins on cuteness ;)

@valtlai
Copy link
Contributor

valtlai commented Mar 24, 2022

:has() is enabled by default in stable Safari 15.4. 🎊

@jpzwarte
Copy link

A checkbox web component:

  • The input is slotted so it integrates with forms and labels
  • The input is hidden and we use SVG to render a custom checkbox
  • When the input has focus & focus-visible, the SVG should have a box-shadow
<span class="box">
  <slot name="input"></slot>
  <svg>...</svg>
</span>
:host(:focus-visible-within) svg {
  box-shadow: ...;
}

Atm, the only solution I see is to use JS.

@i-am-the-slime
Copy link

@jpzwarte Exactly how I ended up here, too.

@jpzwarte
Copy link

@i-am-the-slime I believe this is now possible using :host(:has(:focus-visible)) svg { ... }. Haven't tried it yet though.

@WodarekLy
Copy link

@i-am-the-slime I believe this is now possible using :host(:has(:focus-visible)) svg { ... }. Haven't tried it yet though.

Sadly, :has() does not work in Firefox by default, so this isn't a feasible solution for me. 😭

I think having a :focus-visible-within selector would be tremendously helpful!!!

@bkardell
Copy link
Contributor

bkardell commented Mar 7, 2023

@i-am-the-slime I believe this is now possible using :host(:has(:focus-visible)) svg { ... }. Haven't tried it yet though.

Sadly, :has() does not work in Firefox by default, so this isn't a feasible solution for me. 😭

I think having a :focus-visible-within selector would be tremendously helpful!!!

But :has() is shipping by default in 2 of 3 engines, and is part of Interop 2023 - it is going to be universal comparatively soon. At that point, is there a remaining gap in what you can express (if it feels still slightly a little clunkier to express)? Or is it just sugar on that that you're asking for?

@craigkovatch
Copy link

Well, it's not just sugar, right? Because the clunkier version has a selector specificity of 3, whereas the others are 1. That will make for some awkward rule-writing at some point.

:focus
:focus-visible
:focus-within
:host(:has(:focus-visible))

One of these is not like the others :) I think the dev- and CSS rulewriting-ergonomics here are nontrivial.

@waterplea
Copy link

I doubt you would ever want you :focus-visible styles to have low specificity and be overridden by anything. I came here with basically the same issue of checkbox component-like situation, but it looks like :has indeed has us covered and I believe this ticket can be closed.

@craigkovatch
Copy link

I’m not saying I want them to be low, but it would be nice for them to be consistent and predictable. As the author of a 70+ component UI library for about 6 years now, the predictability benefit extends to people who use and potentially want to override the library, too. It would be nice for them all to be the same.

@waterplea
Copy link

As the author of a 70+ component UI library for about 6 years now.

I can relate 😃 the thing to keep in mind, if that's the way to handle this, it would also be the same selector with same specificity when users want to override it, so I believe has would be a working solution to the issue once Firefox catches up.

@ole-thoeb
Copy link

From my understanding and testing :has inside :host() does not work. So :host(:has(:focus-visible)) is not an option or am I misunderstanding something?

@woody-li
Copy link

woody-li commented Oct 30, 2023

I agree that :has(:focus-visible) is a good solution.

But how to deal with shadow dom?
It's just as ineffective as :has(:focus) for shadow elements (not the slot assigned elements).

@bogger33
Copy link

bogger33 commented Feb 12, 2024

just chiming in for another use case:

<label><input type="file"></label>

with the actual input hidden, and the label styled as a button that doesn't display the file name (e.g. for easy centering)

@bkardell
Copy link
Contributor

I'm adding the agenda+ label here because I think we should resolve to close this issue and perhaps open another about shadow dom if relevant

@astearns astearns moved this to Unsorted in CSSWG June 2024 meeting Jun 3, 2024
@steffchep
Copy link

steffchep commented Jun 20, 2024

I have tried :has(:focus-visible) on the host of a web-component, but it does not seem to work - it gets ignored

here is my attempt:

	:host(:not([disabled]):has(:focus-visible)) {
		outline: 2px solid var(--vs-color-interactive-outline, initial);
		outline-offset: 2px;
		box-shadow: 0px 0px 0px 2px var(--vs-color-main-background);
	}

.some-class:has(:focus-visible) works just fine, but it seems :has does not like :host

So, I would really love to have a :focus-visible-within. Or :has to work with :host :)

Edit: just seen a similar comment further up, apologies!

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Do we need :focus-visible-within ?.

The full IRC log of that discussion <emilio> q+
<TabAtkins> astearns: Brian added a comment just asking to close the issue (and open a different one about shadow dom)
<TabAtkins> dbaron: I think we should punt, people missing probably have strong opinions
<astearns> ack emilio
<TabAtkins> astearns: would be great if those strong opinions were written in to the issue
<TabAtkins> emilio: I know focus does propagate out from shadow trees
<TabAtkins> emilio: :has() mostly covers this, just not when shadow dom is involved
<TabAtkins> emilio: And for that, :focus works, but :focus-visible... probably not?
<TabAtkins> emilio: I think moving it out of the shadow tree would cause undesired outlines
<TabAtkins> emilio: So main question is if people are having to work around this with JS we probably want something like this, but...
<TabAtkins> emilio: I don't see a wya of making it work with shadow dom
<TabAtkins> emilio: Slgihtly against closing because there's a use-case that seems valid, and don't see how it can be addressed without this
<TabAtkins> astearns: So punt on this today. keep the agenda tag on it? or solicit opinions first?
<TabAtkins> astearns: Slgihtly inclined to take the tag off
<TabAtkins> dbaron: I think taking it off is fine, tho I think i'm in the opposite camp of Brian (i think we should add it)

@astearns astearns removed the Agenda+ label Jul 17, 2024
@rgpublic
Copy link

+1 for :focus-visible-within. It's just intuitive and easier to write than :has(...). We already have :focus-within (because you don't always want to style the focus outline on the element itself) and we have :focus-visible (because most of the time you want the focus outline only to appear for keyboard users). These two things are totally separate requirements that have nothing to do with each other. So it should be possible to combine them. I was actually quite surprised to find that :focus-visible-within doesn't exist. If we add :not(...) to the mix we could avoid another nesting-level and keep things simple. Just my 0,02€.

@josepharhar
Copy link
Contributor

Here is a use case for :focus-visible-within for customizable select, based on this demo: https://codepen.io/una/pen/dyBWYxR

Without focus-visible-within, we have to use this selector:

select:has(option:focus-visible)::picker(select)

With focus-visible-within, we could do this instead:

::picker(select):focus-visible-within

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Unsorted
Development

No branches or pull requests