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

Connect HTML spec up to new CSS interactivity property #10956

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mfreed7
Copy link
Contributor

@mfreed7 mfreed7 commented Jan 28, 2025

I was a bit unsure about a few parts of this PR, so help would be appreciated from the editors. The idea is:

  1. Remove duplication - allow the CSS spec to define the concept of "inert".
  2. Make the inert HTML attribute set interactivity:inert via a new UA stylesheet rule.
  3. Make modal dialogs non-inert via an interactivity:auto UA stylesheet rule.
  4. {later} A rule likely needs to be added for fullscreen elements also, setting :fullscreen {interactivity: auto}.

CSS spec is here: https://drafts.csswg.org/css-ui-4/#inertness


(See WHATWG Working Mode: Changes for more details.)


/indices.html ( diff )
/infrastructure.html ( diff )
/interaction.html ( diff )
/interactive-elements.html ( diff )
/rendering.html ( diff )

Copy link
Contributor Author

@mfreed7 mfreed7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review!

@nt1m
Copy link
Member

nt1m commented Jan 30, 2025

I think blocked by a modal dialog should be defined in terms of interactivity (either set as a presentational hint on the root, or using an UA stylesheet rule), because otherwise dialog:modal { interactivity: auto } won't do anything (because auto is the default value. I don't think this is what the current HTML spec PR does.

@mfreed7
Copy link
Contributor Author

mfreed7 commented Jan 30, 2025

I think blocked by a modal dialog should be defined in terms of interactivity (either set as a presentational hint on the root, or using an UA stylesheet rule), because otherwise dialog:modal { interactivity: auto } won't do anything (because auto is the default value. I don't think this is what the current HTML spec PR does.

I added a Note about this. But I think the concept (agreed to over in CSSWG I believe) was that both specs can set something to be inert. The problem with defining modal dialog behavior in terms of CSS is that it allows author CSS to make parts of the page "un-inerted", which is undesirable. And it can't be set to interactivity:inert/auto !important to avoid that problem, because then that doesn't allow the author to "re-inert" the dialog itself.

@lilles
Copy link
Contributor

lilles commented Jan 30, 2025

I think blocked by a modal dialog should be defined in terms of interactivity (either set as a presentational hint on the root, or using an UA stylesheet rule), because otherwise dialog:modal { interactivity: auto } won't do anything (because auto is the default value. I don't think this is what the current HTML spec PR does.

I added a Note about this. But I think the concept (agreed to over in CSSWG I believe) was that both specs can set something to be inert. The problem with defining modal dialog behavior in terms of CSS is that it allows author CSS to make parts of the page "un-inerted", which is undesirable. And it can't be set to interactivity:inert/auto !important to avoid that problem, because then that doesn't allow the author to "re-inert" the dialog itself.

Another issue is that no one's been able to come up with UA styles that actually works with shadow DOM.

Copy link
Collaborator

@noamr noamr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've stumbled upon this type of problem when implementing moveBefore things... Thanks for working on this! Added some non-authoritative nits

Copy link
Contributor Author

@mfreed7 mfreed7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the comments!

Copy link
Member

@domenic domenic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with nits. This turned out pretty nice; thanks for iterating!

Let me know when the checkboxes in the OP are filled out.

@domenic domenic added topic: style integration Better coordination across standards needed topic: dialog The <dialog> element labels Feb 21, 2025
@mfreed7
Copy link
Contributor Author

mfreed7 commented Feb 21, 2025

LGTM with nits. This turned out pretty nice; thanks for iterating!

Let me know when the checkboxes in the OP are filled out.

Thanks for the review!

  • At least two implementers are interested (and none opposed):

@annevk @emilio would you mind please providing support for landing this?

@mfreed7
Copy link
Contributor Author

mfreed7 commented Feb 21, 2025

@scottaohara @aleventhal does this need any change to the HTML AAM spec? This PR (to HTML) doesn't actually change the behavior of existing things like inert or modal dialogs. The CSSWG spec change (which already landed, here) might need something?

@annevk
Copy link
Member

annevk commented Feb 24, 2025

What is the status of this in the CSS WG? It's relatively straightforward to get things in drafts, but that historically hasn't really conveyed any kind of stability.

source Outdated
@@ -135626,6 +135652,14 @@ dialog:popover-open {
display:block;
}

:modal {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct? When you have multiple modal elements in the top layer, don't all match :modal? You need a magic "topmost modal" thing here, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I don't think so. Yes, this sets the interactivity to auto for all dialogs, but see the <dfn>blocked by a modal</dfn> section. In particular, there are some Notes about this behavior there. That section blocks all but the topmost via "html inertness". This CSS rule is here just to allow authors to re-override interactivity back to inert if they so desire.

@mfreed7 mfreed7 added the agenda+ To be discussed at a triage meeting label Feb 26, 2025
@past past removed the agenda+ To be discussed at a triage meeting label Feb 27, 2025
@chrishtr
Copy link
Contributor

What is the status of this in the CSS WG?

In terms of the CSSWG's process (which follows W3C practices), it is in an editor's draft. There have been multiple CSSWG consensus resolutions, such as to add it and decide on behaviors like interaction with the top layer.

@astearns
Copy link

astearns commented Mar 6, 2025

What is the status of this in the CSS WG?

In terms of the CSSWG's process (which follows W3C practices), it is in an editor's draft. There have been multiple CSSWG consensus resolutions, such as to add it and decide on behaviors like interaction with the top layer.

But (IMO) we should not consider anything in CSSWG drafts as stable until there is at least a prototype and some tests. Lack of unresolved issues before that happens does not mean much

@mfreed7
Copy link
Contributor Author

mfreed7 commented Mar 6, 2025

But (IMO) we should not consider anything in CSSWG drafts as stable until there is at least a prototype and some tests. Lack of unresolved issues before that happens does not mean much

Just to put it here, Blink has implemented this property, and written the WPTs:

https://wpt.fyi/results/css/css-ui?label=master&label=experimental&aligned&q=interactivity

@css-meeting-bot
Copy link

The CSS Working Group just discussed Connect HTML spec up to new CSS `interactivity` property.

The full IRC log of that discussion <past> https://github.com//pull/10956
<hdv> masonf: quick intro… this is two sets of specs (CSS, HTML) for a new property called `interactivity`, works like `inert` in HTML, there's a spec PR in HTML that connects this up
<hdv> masonf: both sides have some control here… HTML has a way to make things inert, CSS does too now, HTML can interconnect the two
<hdv> masonf: and make sure overriding works as expected
<hdv> masonf: this was editorially reviewed, am looking for implementor support
<hdv> masonf: for both parts, HTML and CSS
<lwarlow> q+
<emilio> q+
<hdv> annevk: what i'd like input from CSSWG… atm we take something with dep on HTML spec, it's the equivalent to CR spec in W3C land, taking a dependency in your work, if it breaks something you're invalidating implementations
<hdv> fantasai: if something is in CR, it's def very stable. If not, it's not clear where it is in terms of stability
<hdv> fantasai: we do have CSS snapshots, to show where things are
<hdv> fantasai: also have availability to show 'these things are not in CR but stable enough to ship'
<hdv> fantasai: kind of the only tool we have to indicate stability beyond CR flag
<hdv> fantasai: sometimes a feature was worked on by one team but others haven't seen it yet, that convo prompts people to look at it and they might find design issue or issues that weren't paid attention to
<hdv> fantasai: if you want something at the level of super stable, we can have that conversation
<hdv> ack luke
<hdv> ack lw
<hdv> lwarlow: the propery name seems ambiguous
<hdv> s/propery/property
<hdv> lwarlow: makes me feel iffy re: what it wants to do in the future and if this naming allows it
<hdv> lwarlow: maybe interactivity is clearer and I haven't read enough… interactivity doesn't _just_ mean is it inert or not… eg see focusability… there's a desire to have a CSS way to cover focusability, is that part of it or separate?
<hdv> ack em
<hdv> emilio: one of the comments on the PR was re the model
<hdv> emilio: it feels iffy to deal with some things via CSS and with others, have it automatic, like auto
<hdv> emilio: makes it a bit harder to reason about
<masonf> q+
<hdv> emilio: if you're fine with that, seems fine implementation wise
<past> ack masonf
<fantasai> s/availability to show/capability in Snapshot to show for individual features,/
<hdv> masonf: pretty strong push from the a11y folks, reason the value is auto is… for somebody to be able to do body { /* set it to auto */ } would break all sorts of accessibility
<hdv> emilio: there are other ways to do that… eg you could set important but would be annoying
<hdv> emilio: if the spec could make that clearer, eg this is weird but this is why it is weird, would be ok. It's a bit annoying implementation wise, but it's okay
<hdv> emilio: no concerns
<hdv> masonf: can't really use !important either, you need to be able to re-inert a modal dialog via CSS
<hdv> emilio: yes is weird
<hdv> emilio: right now, webkit effectively has inheriit bit in the style object, basically an internal property
<hdv> emilio: now, with a value on top of that… doesn't inert in HTML have similar concert?
<hdv> s/concert/concerns
<hdv> masonf: but then it's a developer side thing, modals are a bit more special I guess
<hdv> emilio: not sure if I agree but its ok
<hdv> masonf: just parroting what I've heard
<hdv> panos: so this room's concensus is this is ok to move forward with?
<hdv> emilio: I'm okay with that
<hdv> olli: if you make something inert and focus is in that area, what happens to the focus?
<hdv> emilio: same as if you make it visibility hidden or something else
<hdv> annevk: what did you mean with move forward?
<hdv> panos: is everyone ok with CSS side of things?
<hdv> masonf: comment on weird side of things probably belongs in HTML
<hdv> annevk: Luke brought op the name of the property, that seems essential for both specs
<hdv> annevk: and we probably need good idea of what stability means on the CSS side
<hdv> annevk: at TC39 we know stability/consensus within the group; it'd be trivial to organise the HTML stuff around that, but in CSS it's less clear
<past> q?
<hdv> fantasai: I think we can make it more clear,doing it more rigorously?
<fantasai> s/doing it/just need to use Snapshot/
<hdv> masonf: does TC39 refer out to other specs and if so how? what we're discussing here is interdepencies of specs?
<hdv> annevk: how?
<hdv> masonf: release process was independent in the past
<hdv> annevk: at TC39 usually have dependencies but one way, we know at which point it has a state where TC39 is happy about it
<hdv> annevk: we want to avoid building on quicksand in this situation
<hdv> past: is it okay for CSS WG to discuss internally and give out a signal that WHATWG can use as a stability indicator?
<hdv> astearns: personally I think we should be careful about referencing something in a CSS spec assuming it is stable
<hdv> astearns: lack of issues is one thing, usually issues come up when people try implementing something. I don't think this property has prototypes yes
<hdv> masonf: it's fully implemented in Chromium and there are WPTs
<hdv> astearns: in that case my concern is less, may be stable enough to reference
<hdv> fantasai: I think it should be put in a snapshot… changes may happen due to more people looking at it… putting it into a snapshot could be a way to get people to chime in
<fantasai> https://www.w3.org/TR/css/#CR-exceptions
<hdv> astearns: we also had things ready to ship even if not ready completely yet
<hdv> past: any other thoughts or feedback?
<hdv> past: this seems like a question for CSSWG to answer
<astearns> s/even if not/even if the whole module is not/
<fantasai> s/may happen/happen in response to implementation, but also in response to/
<hdv> past: sounded like you were waiting for implementor feedback, masonf ?
<hdv> masonf: yes
<hdv> emilio: without my mozilla hat on, sounds good to me
<hdv> olli: I need to review the PR

@emilio
Copy link
Contributor

emilio commented Mar 6, 2025

Given what we discussed today this looks good to me, but we should make very clear that the "make modal dialogs not overridable, but inert attribute overridable" is intentional.

source Outdated
&lt;dialog>&lt;/dialog>
&lt;/div></code></pre>

<p>The reason that HTML "overrides" the <span data-x="css-interactivity">'interactivity'</span>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emilio I added this chunk as a result of today's discussion. LMK if that helps or hurts.

@mfreed7
Copy link
Contributor Author

mfreed7 commented Mar 6, 2025

Given what we discussed today this looks good to me, but we should make very clear that the "make modal dialogs not overridable, but inert attribute overridable" is intentional.

Great, thanks! I've checked the checkbox in the OP based on this comment.

I also added a paragraph of more motivation for the "weird" behavior. LMK what you think.

@domenic
Copy link
Member

domenic commented Mar 7, 2025

All the boxes here looked checked, but agreement is fresh off the presses and maybe people want to review the new note.

We haven't gotten an answer back on whether this affects HTML-AAM / ARIA, but I am pretty sure it doesn't since there's no new HTML attributes or elements involved.

I'll plan on merging this mid-next-week, assuming @mfreed7 addresses my nit and rebases on master to resolve conflicts by then.

@annevk
Copy link
Member

annevk commented Mar 7, 2025

No, this cannot merge. The CSS side still has open issues and the CSS WG has not indicated this is stable to reference.

@annevk annevk added the do not merge yet Pull request must not be merged per rationale in comment label Mar 7, 2025
@domenic
Copy link
Member

domenic commented Mar 7, 2025

We don't have any items in our working mode for "the CSS side has open issues" or blocking on W3C process. I believe we meet all the criteria in https://whatwg.org/working-mode#additions and https://whatwg.org/working-mode#changes . Can you point to which one is not met?

@emilio
Copy link
Contributor

emilio commented Mar 7, 2025

w3c/csswg-drafts#11849 is Luke's issue (for cross-referencing purposes)

I was a bit unsure about a few parts of this PR, so help would be
appreciated from the editors. The idea is:
 1. Remove duplication - allow the CSS spec to define the *concept*
    of "inert".
 2. Make the `inert` HTML attribute set `interactivity:inert` via
    a new UA stylesheet rule.
 3. Make modal dialogs non-inert via an `interactivity:auto` UA
    stylesheet rule.
 {eventual step 4} A rule likely needs to be added for fullscreen
    elements also, setting `interactivity:auto`.

Fix reference

Add a bunch of notes, and refactor some things

Address comments

Start on "marked as explicitly inert"

Semi-revert the "marked as explicitly inert" approach, and tweak

Resolve nits

Add more to the Note about why the behavior is the way it is

Address nit

Merge fixup

Final
@mfreed7
Copy link
Contributor Author

mfreed7 commented Mar 7, 2025

We haven't gotten an answer back on whether this affects HTML-AAM / ARIA, but I am pretty sure it doesn't since there's no new HTML attributes or elements involved.

I'm pretty sure too, but @scottaohara did mention to me yesterday that he'd take a look at this soon. I'm ok waiting for that, just to confirm.

I'll plan on merging this mid-next-week, assuming @mfreed7 addresses my nit and rebases on master to resolve conflicts by then.

Ok, I addressed the nit, and rebased. The rebase wasn't super clean, given the dialog closedby changes, but I think I got it fixed up correctly. An extra pair of eyes wouldn't hurt.

@alice
Copy link
Contributor

alice commented Mar 17, 2025

This is really disappointing to see. I thought the discussion on #10811 was really promising.

@mfreed7
Copy link
Contributor Author

mfreed7 commented Mar 17, 2025

This is really disappointing to see. I thought the discussion on #10811 was really promising.

Sorry to hear that. The discussion on #10811 was hypothetical and (I think?) could still be moved forward if we wanted to. It describes a way to have explicit exceptions for other top layer things like popovers while there's a modal dialog open. My understanding from several comments on that issue was that this situation wasn't desirable from an a11y perspective, so this PR didn't change the modal dialog behavior. Can you comment? E.g. this comment mentions that this might violate screen reader assumptions, and the comments about re-parenting things in the a11y tree scared me a bit. Perhaps those aren't as scary as they sound?

@scottaohara
Copy link
Collaborator

from what i can tell, reading this PR over a few times now, is that i don't see anything in here that would necessarily need to be changed in the HTML AAM or CORE AAM specs - unless there are mappings that were altered that wouldn't be called out in this HTML spec update?

As I mentioned in my initial comment about the use cases i had for allowing something to escape inertness - I wasn't wedded to the idea that it needed to be done via CSS. I'm not against it, but I'm also not a strong supporter of it being the solution here.

The back and forth with Alice in #10811 seemed promising - specifically allowing popovers to escape inertness, and then essentially adjusting them in the a11y tree - much like aria-owns does - to make it seem to people using AT that the popover was a child of the current modal dialog.

So, I guess with all that said, I'm not sure about allowing for inertness to be escaped if we already have one potential solution which would arguably be a lot safer / better for the end user experience. For my other use cases, while I still think they're valid, I think it's probably a better idea to see if there aren't other potential solutions, than introducing an inert escape hatch that can never be closed once open. Because use cases aside, @alice is right that this could be problematic if unchecked. If this PR can go through without the ability to uninert things for now, that'd be the safer option, imo.

@alice
Copy link
Contributor

alice commented Mar 18, 2025

It describes a way to have explicit exceptions for other top layer things like popovers while there's a modal dialog open.

That's not how I had envisioned it. The way I proposed and understood it (and it seemed like you agreed) was that it would both explain how dialogs and fullscreen elements made the rest of the page inert, and fix the issue with content in a top layer on top of dialogs being made inert erroneously.

It would also open the door to exploring better ways to implement custom modal UI without the need to use <dialog> or inert (and thus with no need to add the capacity to escape inert here).

E.g. this comment mentions that this might violate screen reader assumptions, and the comments about re-parenting things in the a11y tree scared me a bit. Perhaps those aren't as scary as they sound?

Those are implementation details needed to make the a11y tree semantics match the dialog semantics, and would be needed regardless (i.e. if the browser didn't do this, the author using popover with either a <dialog> or any custom dialog which used role=dialog would have to, and they most likely wouldn't know to).

@scottaohara
Copy link
Collaborator

scottaohara commented Mar 18, 2025

i'm currently looking at the mdn draft for the customizable select, and in it a passing comment was mentioned that the inert button part of the select could have its inertness undone using the CSS interactivity property. That button part was made inert on purpose. The HTML AAM mappings specifically call it out as inert and that as far as the a11y tree is concerned, the select/button part should not be perceived as two separate elements to end users - why would authors be allowed to undo that with CSS?

@smhigley
Copy link

I'm catching up here and in #10811 and wanted to add a few thoughts --

I think the idea of a CSS opt-out of inert makes me nervous, especially one that differs in behavior depending on what has made the element is inert (i.e. because of an ancestor style vs. a modal dialog). In practice, in a dev environment with code contributions from many different teams (as in any medium-to-large organization), it's easy to have controls from different sources using different methods to inert background content. One dialog might easily be an HTML <dialog>, and another a custom dialog component using inert or the new CSS style. Or, as in the case of the UI library I work on, we might do things like convert our shipped Dialog control from a custom solution to one using <dialog> in a version update.

In that environment, if another control (e.g. a notification popup) sets the interactivity style, that would be exceedingly frustrating to debug and maintain since it might work with some dialogs but not the others. Conversely, a control that incorrectly sets interactivity: auto would still work fine with a <dialog> element but not the custom control. This difference in behavior would, in my opnion, make the style effectively verboten since you (a theoretical component dev) can't control or predict how it'll behave re: other inerting controls on the page that you have no control over. I also don't really think it's reasonable to expect regular non-standards-participating developers to understand the distinction between HTML dialog inert-ness and CSS inert-ness in practice.

There's also the issue that exempting modal dialogs from being able to be escaped does away with the most common use cases mentioned so far. Going back to @scottaohara's examples, two of the three would require being able to escape dialogs.

So having said all that, the reason I think I'm opposed to adding any inert escape via CSS rather than having CSS also escape dialogs is:

  • Providing screen reader access to controls outside a modal dialog is more complicated than just putting them in the accessibility tree. Multiple screen readers either hard- or soft-restrict the cursor to an open dialog, so even if something else were escaped and in the a11y tree, it still wouldn't necessarily be reachable. VoiceOver is the strictest about this I believe, and won't even expose live region changes outside of a dialog, even if they are in the a11y tree. This is essentially what I was chatting with Alice about earlier, which she referenced in this comment
  • Having any control on the page able to escape being inert-ed by an open dialog based on style specificity just feels like opening the door to chaos. It introduces a war between different elements trying to make their inert styles win out, essentially moving the accessibility aspect of top-layer management into CSS.

I really like the suggestion made in #10811 around re-parenting other top-layer nodes into a dialog (at least for the top-layer nodes that are on top of the dialog), and having that be the "escape" for inert. That seems both much easier to manage for web authors, and also much less of a hidden foot-gun for accessibility. It does seem like both this potential approach and other options for escaping inert need more exploration before landing on one, though.

TL;DR: inert is such a powerful tool for either helping or destroying accessibility that combining it with an authoring experience that is hard to understand and easy to misuse seems like a recipe for disaster.

@mfreed7
Copy link
Contributor Author

mfreed7 commented Mar 20, 2025

Hi, I’ve tried below to answer all questions. Because there were many, this got quite long. Apologies for length or if I missed anything!

from what i can tell, reading this PR over a few times now, is that i don't see anything in here that would necessarily need to be changed in the HTML AAM or CORE AAM specs - unless there are mappings that were altered that wouldn't be called out in this HTML spec update?

Great! Thanks for that - based on this comment I’ve checked the last box on this PR.

As I mentioned in my initial comment about the use cases i had for allowing something to escape inertness - I wasn't wedded to the idea that it needed to be done via CSS. I'm not against it, but I'm also not a strong supporter of it being the solution here.

I agree there are use cases - e.g. a “user space” modal dialog that doesn’t utilize the top layer. Currently, that’s typically implemented using manual focus trapping, which is worse for a11y and correctness.

The back and forth with Alice in #10811 seemed promising - specifically allowing popovers to escape inertness, and then essentially adjusting them in the a11y tree - much like aria-owns does - to make it seem to people using AT that the popover was a child of the current modal dialog.

My concerns are twofold: First, I wonder if the better “solution” to that problem is to require developers to simply nest the popover within the dialog. That provides out-of-the-box inertness and a11y. Second, I worry about the implementability of making the a11y tree not match the DOM tree in such a significant way. I know that Blink has had a long series of bugs related to situations like this, and we’d like to avoid more of them. + @aleventhal for comments based on experience here.

I think it's probably a better idea to see if there aren't other potential solutions, than introducing an inert escape hatch that can never be closed once open.

Are there other solutions that are better? It seems that the crux of the issue isn’t really the shape of how something gets un-inerted, but more that it can be un-inerted at all.

If this PR can go through without the ability to un-inert things for now, that'd be the safer option, imo.

Technically, this PR doesn’t add un-inerting behavior (that behavior is in the CSS spec). On the contrary, this PR goes to some length to preserve the existing behavior wherein modal dialog related inertness cannot be un-inerted.

That's not how I had envisioned it. The way I proposed and understood it (and it seemed like you agreed) was that it would both explain how dialogs and fullscreen elements made the rest of the page inert, and fix the issue with content in a top layer on top of dialogs being made inert erroneously.

It would also open the door to exploring better ways to implement custom modal UI without the need to use <dialog> or inert (and thus with no need to add the capacity to escape inert here).

Can you help me understand your approach a bit better? Reading your comment and the ones below, it seems to just say that modal dialogs form a “blocking” top layer item, which un-inert the things above them in the stack, and inert everything below them. That still feels like magic (i.e. it doesn’t explain in the sense of other developer-visible APIs) and also requires the use of the dialog element and the UA-provided top layer. I.e. it doesn’t allow userspace modals that aren’t in the top layer. Please help me understand my disconnect.

Those are implementation details needed to make the a11y tree semantics match the dialog semantics, and would be needed regardless (i.e. if the browser didn't do this, the author using popover with either a <dialog> or any custom dialog which used role=dialog would have to, and they most likely wouldn't know to).

One nice thing about the existing behavior of popovers and modal dialogs is that it in fact does require the developer to properly nest the popover within the dialog, or it’ll be inert and won’t work. I’m concerned about making the implementation of the a11y more convoluted, for fear of introducing major bugs and crashes and things, which aren’t good for users.

i'm currently looking at the mdn draft for the customizable select, and in it a passing comment was mentioned that the inert button part of the select could have its inertness undone using the CSS interactivity property. That button part was made inert on purpose. The HTML AAM mappings specifically call it out as inert and that as far as the a11y tree is concerned, the select/button part should not be perceived as two separate elements to end users - why would authors be allowed to undo that with CSS?

This was simply a general effort to avoid !important on the UA stylesheet for customizable-<select>. There might be uncommon use cases where the button wants to be made back into a button, hopefully with careful consideration of a11y and use of ARIA. But I would consider this a fairly corner case, and not likely to be hit by developers on accident or without noticing.

I think the idea of a CSS opt-out of inert makes me nervous, especially one that differs in behavior depending on what has made the element is inert (i.e. because of an ancestor style vs. a modal dialog). In practice, in a dev environment with code contributions from many different teams (as in any medium-to-large organization), it's easy to have controls from different sources using different methods to inert background content. One dialog might easily be an HTML <dialog>, and another a custom dialog component using inert or the new CSS style. Or, as in the case of the UI library I work on, we might do things like convert our shipped Dialog control from a custom solution to one using <dialog> in a version update.

So I think one nice thing about the current PR is that the mechanism for un-inerting is always the same: interactivity: auto. That’s true whether the inertness was provided by the inert attribute or interactivity: inert. Of course, the one exception is modal <dialog>s, and that exception was preserved precisely and only to maintain the a11y guarantees that it already provides.

In that environment, if another control (e.g. a notification popup) sets the interactivity style, that would be exceedingly frustrating to debug and maintain since it might work with some dialogs but not the others. Conversely, a control that incorrectly sets interactivity: auto would still work fine with a <dialog> element but not the custom control. This difference in behavior would, in my opnion, make the style effectively verboten since you (a theoretical component dev) can't control or predict how it'll behave re: other inerting controls on the page that you have no control over. I also don't really think it's reasonable to expect regular non-standards-participating developers to understand the distinction between HTML dialog inert-ness and CSS inert-ness in practice.

I think I need more help understanding the problematic cases here. Basically, there seem to be two types of interaction implementations: one in which modal <dialog> elements are used, and another where they aren’t. In the former case, those modal dialogs will always do the right thing - they’ll be non-inert while the rest of the page is inert. In the latter case, it’ll be up to the site to properly inert and un-inert the page and the “dialog”, regardless of the mechanism used for “inert”. If it’s the platform, they’ll have to get their interactivity properties set up correctly. If it’s totally user-space, they’ll have to make sure their JS code that handles focus trapping is done correctly. There is a potential for footguns in either approach. But I don’t think it helps to always require userspace modal implementations to also build their own focus trapping. That would seem to create two footguns rather than one, wouldn’t it?

There's also the issue that exempting modal dialogs from being able to be escaped does away with the most common use cases mentioned so far. Going back to @scottaohara's examples, two of the three would require being able to escape dialogs.

I agree, use cases 2 and 3 there would not be able to use a native modal <dialog> element, and would instead need to use the interactivity property to inert and de-inert the proper elements.

So having said all that, the reason I think I'm opposed to adding any inert escape via CSS rather than having CSS also escape dialogs is:

Oh, I guess you are supportive of escaping the inertness of modal-<dialog>. Can you please confirm?

  • Providing screen reader access to controls outside a modal dialog is more complicated than just putting them in the accessibility tree. Multiple screen readers either hard- or soft-restrict the cursor to an open dialog, so even if something else were escaped and in the a11y tree, it still wouldn't necessarily be reachable. VoiceOver is the strictest about this I believe, and won't even expose live region changes outside of a dialog, even if they are in the a11y tree. This is essentially what I was chatting with Alice about earlier, which she referenced in this comment

Help me understand - this sounds like a reason not to allow escaping modal <dialog> inertness.

  • Having any control on the page able to escape being inert-ed by an open dialog based on style specificity just feels like opening the door to chaos. It introduces a war between different elements trying to make their inert styles win out, essentially moving the accessibility aspect of top-layer management into CSS.

I guess same question as above - this sounds like a reason not to allow escaping.

TL;DR: inert is such a powerful tool for either helping or destroying accessibility that combining it with an authoring experience that is hard to understand and easy to misuse seems like a recipe for disaster.

This is a good thing to be concerned about. I think the documentation needs to be clear. And to me, these three points encapsulate the behavior:

  1. Modal dialogs make the page inert, and the dialog contents non-inert. This behavior cannot be overridden.
  2. The inert attribute simply sets interactivity: inert on the element.
  3. The interactivity property can be used to set an element and its descendants to be inert (interactivity: inert) or un-inert (interactivity: auto).

While it’s three bullets instead of one, it still feels fairly understandable to me.

@alice
Copy link
Contributor

alice commented Mar 21, 2025

I wonder if the better “solution” to that problem is to require developers to simply nest the popover within the dialog.

To clarify, does that mean you now support my proposal that popovers outside of the currently showing modal <dialog> should not be rendered on top of it?

I would still be fine with that, and I agree it gets around having to write more complicated code for the accessibility tree. That would still mean that use case doesn't justify the inert-escaping behaviour that's being pushed here.

Can you help me understand your approach a bit better? Reading your comment and the ones below, it seems to just say that modal dialogs form a “blocking” top layer item, which un-inert the things above them in the stack, and inert everything below them. That still feels like magic (i.e. it doesn’t explain in the sense of other developer-visible APIs) and also requires the use of the dialog element and the UA-provided top layer.

It explains in the sense that it ties un-inerting to a lower-level concept, the top layer, rather than being specific to the <dialog> element. That would mean that other ways to add things to the top layer, including popover and any other future features which use the top layer, could easily be modified to allow inerting behaviour. Unlike the current language, it doesn't require <dialog> necessarily.

What it does do, unlike this proposal, is inherently tie "everything-else-inerting" to a visual indication that content is non-interactive. Content in the top layer, particularly a top layer with a backdrop style, visually obscures content in lower layers.

it doesn’t allow userspace modals that aren’t in the top layer.

I'm fine with that. Obviously, any page-level modal should be in the top layer anyway, so that it doesn't conflict with other top layer elements.

"Component modals" seem to be doing a lot of heavy lifting at this point as a justification for this API. Is that really a user need so urgent we can't, as Scott suggested, take a moment to look at alternatives? Are we really that sure, even, that this API is a good solution for those? Were any alternatives explored at all for that problem?

(Oh, sorry, UI tours too. Same comments apply.)

Technically, this PR doesn’t add un-inerting behavior (that behavior is in the CSS spec). On the contrary, this PR goes to some length to preserve the existing behavior wherein modal dialog related inertness cannot be un-inerted.

It does add un-inerting behaviour for the inert attribute, though. Besides, the CSS PR already landed, so it seems unlikely any comments there would be addressed.

This is a good thing to be concerned about. I think the documentation needs to be clear.

I think you have a lot more faith in developers to read and absorb accessibility guidance than I do. The unfortunate reality is that a significant number of developers won't consider accessibility concerns at all, much less take the time to read the documentation. If it looks good, that's what ships. We can't fix that problem across the board, but we can at least do our best to avoid footguns that are almost certain to harm users.

@scottaohara, @smhigley and I are all advocating not rushing into this API, and you've acknowledged at least some of these concerns as valid. Please don't misconstrue this as a simple request for additional documentation.

@lukewarlow
Copy link
Member

lukewarlow commented Mar 21, 2025

https://jsfiddle.net/056qswnh/ - take this demo for example (relies on chrome 135), clicking on the popover above the dialog's button triggers that button, despite a popover visually being on top. Clicking outside the popover closes the popover but not the light dismissable dialog, despite the fact all other pointer events get swallowed down to the dialog?

I just don't know how to explain this behaviour. Using interactivity also doesn't solve this problem nor explaining of the behaviour. Meanwhile if I have a custom modal dialog I can easily set interactivity: auto on the popover and it just work. Are we just going to prolong the situation where people use custom modal implementations rather than native dialog?

I agree that if a popover is opened in the top layer above the dialog but is inert it shouldn't render. Else you end up with a very confusing user experience.

I wonder if the better “solution” to that problem is to require developers to simply nest the popover within the dialog. That provides out-of-the-box inertness and a11y.

One other possibility of an escape hatch would be based on the popovers invoker DOM location. IIRC the location of the popover doesn't really matter for anything else in the popover API (e.g. nesting behaviour). If the invoker is a dialog child perhaps that's enough of a signal that actually that popover should work correctly even though it's outside the dialog in the DOM?

For the cases like toasts where there isn't a trigger element, you could still do something like .showPopover({source: dialog}) to get that escape hatch?

That is if we didn't want to just do this magically for all popovers opened after a dialog is (and thus being above it in the top-layer). I'm unaware of the potential implementation complications but the fact we already do focus order changes based on the invoker suggests we could do other such changes?

Now I'm not saying allowing people to uninert modal dialogs whenever they want is a good thing. But if they can do common things for their custom dialog (or by using a non-modal dialog that they then hijack into a "modal") but not with the built-in it feels like another reason people would not use the built-in. That's a shame given all the hardwork that's gone into making real dialogs great (command/commandfor, close watchers, optional light dismiss etc).

If we could build these escape hatches into the system it would be good. Now I realise some of this is tangential to the point of this PR but the new author control does introduce a new angle to look at this.

@scottaohara
Copy link
Collaborator

some quick responses:

  • it is a good thing that modal dialog intertness cannot be undone with CSS interactivity.
  • per the popover / modal dialog use case - just making the popover escaping inertness would not be enough to solve the use case. it would also have to become an accessibility child of the modal dialog to meet user expectations. i hope these two points clarify any ambiguity over what people expect. aka - modal inertness should not be able to be undone with css.
  • i am happy to see that the UA stylesheet for customizable select was updated so that a web author could not undo the button part's inertness.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
do not merge yet Pull request must not be merged per rationale in comment integration Better coordination across standards needed topic: dialog The <dialog> element topic: style
Development

Successfully merging this pull request may close these issues.