Skip to content

[focusgroup] Add the focusgroup attribute #11723

Open
janewman wants to merge 120 commits intowhatwg:mainfrom
janewman:focusgroup
Open

[focusgroup] Add the focusgroup attribute #11723
janewman wants to merge 120 commits intowhatwg:mainfrom
janewman:focusgroup

Conversation

@janewman
Copy link
Copy Markdown

@janewman janewman commented Sep 29, 2025

#11641

This adds the focusgroup attributes needed to allow for declarative focus navigation using the directional navigation (arrow keys, d-pad).
This specs the behavior detailed in the explainer on OpenUI.


/dom.html ( diff )
/index.html ( diff )
/infrastructure.html ( diff )
/interaction.html ( diff )

@janewman janewman marked this pull request as ready for review November 24, 2025 17:33
@janewman
Copy link
Copy Markdown
Author

Opening up for review, but please keep in mind this is an early draft.

@janewman
Copy link
Copy Markdown
Author

@annevk, during TPAC you expressed interest in taking a look at this draft spec change - I would really appreciate any feedback you had as I work to move this towards something we think accurately captures the behavior and fits in with the existing logic.
Thanks!

@smaug----
Copy link
Copy Markdown

It is unclear to me what happens if the page has keydown, or keyup event listener and calls preventDefault() when arrow key is used. Which event listener has some affect and which doesn't?
What if some modifier is used with the key event?

…ng section, improve segment definition with example, and simplify key conflict element handling
@janewman
Copy link
Copy Markdown
Author

janewman commented Feb 2, 2026

It is unclear to me what happens if the page has keydown, or keyup event listener and calls preventDefault() when arrow key is used. Which event listener has some affect and which doesn't? What if some modifier is used with the key event?

I've added a new section that should answer all of these questions, please let me know what you thank and if it still isn't clear.
Thanks for all of the feedback, it is very much appreciated!!

@janewman janewman requested a review from smaug---- February 2, 2026 23:39
zcorpan and others added 27 commits March 27, 2026 21:06
When a Location object is created, a Document is not yet created. This is problematic for ancestorOrigins.

Also remove `[SameObject]` since step 1 can return a separate object.
Need to pass this and the given value to the set the inner text steps algorithm.
They were moved from UI Events to Pointer Events, see: w3c/pointerevents#564 & w3c/uievents#411.
Reject the promise instead of returning to avoid a "deadlock" with `await navigation.back().finished`.

Fixes whatwg#12028.
This moves most of the HTMLHyperlinkElementUtils to a new HyperlinkElementUtils mixin, except for the href IDL and getter algorithm.

The "update href algorithm" and "set the url" algorithm are now declared by the implementing type not as part of HyperlinkElementUtils, this is so that SVG's `<a>` can correctly define it's own algorithms.

Likewise the href IDL and getter steps can't be shared because SVG's IDL is different and a MathML `<a>` won't want the stringifier behaviour on its href.

See whatwg#12063
The changes in whatwg#11450 inadvertently removed the minus sign in front of the default value for the tabIndex getter.
* Markup: lowercase tag-name
* Wording: make the "update href" setup more conventional
* Spelling: insert apostrophe-s
This PR introduces extended lifetime shared workers as a lightweight alternative to e.g., Service Workers, to perform complex, async operations after document unloading. Specifically, this PR introduces the SharedWorkerOptions dictionary and its extendedLifetime boolean member. Together, they allow a SharedWorkerGlobalScope's lifetime to be extended by an implementation-defined time, when it would otherwise be suspendable.

Before this, a shared worker whose owner set is empty or contains only non-fully-active owners would not be "actively needed" or "protected"; it would be thus suspendable for the duration of its https://html.spec.whatwg.org/#between-loads-shared-worker-timeout, or for as long as it has clients, respectively. This is useful for keeping the worker around for a bit so that it doesn't need to be re-initialized from scratch later, but it doesn't guarantee that the worker can perform any last-minute work in this period. Extended lifetime shared workers allow the worker to stay "actively needed" and thus not "suspendable" during the extended lifetime timeout. This ensures they keep running until the timeout expires.

---------

Co-authored-by: Dominic Farolino <domfarolino@gmail.com>
Currently, MessageEvent's origin holds a serialized origin. In order for Origin.from(...) to function as intended for sources with opaque origins, we need to hold an origin on MessageEvent instead.

This patch adds an "origin" concept to `MessageEvent`, and shifts call sites to initialize that value with an origin whenever possible. It also adjusts the "extract an origin" steps to return the stored origin when present, and to return null in cases where the object was initialized with an untrusted origin representation (e.g., when its constructor is called with a MessageEventInit dictionary).

Closes whatwg#11993.
This change allows select elements with the multiple attribute to be rendered as a drop-down box when the author explicitly sets the size attribute to 1.

The related issue should be resolved by suggesting that mobile browsers and desktop browsers both follow these rules in order to improve cross-platform compatibility.

Fixes whatwg#8189.
This aligns `ancestorOrigins` exposure with referrer policy when using the `iframe referrerpolicy` attribute, so an embedder can prevent revealing its own origin to embedded documents. If an `<iframe>` uses `referrerpolicy="no-referrer"` or `same-origin` (and the parent and child are cross-origin), the parent’s origin and any same-origin ancestors are replaced with opaque origins (until reaching an ancestor that is cross-origin). Other policies continue to expose full origins.

This approach keeps existing behavior by default (for web compat) while addressing privacy concerns with an opt-out.

The algorithm reuses the parent's existing list of ancestor origins, avoiding synchronous cross-process lookups and ensuring a stable snapshot even if ancestors mutate their `referrerpolicy` attributes later.

Fixes whatwg#1918. Closes whatwg#2480.
Instead of having a "scripting flag" and then "fixing" scripts in createContextualFragment(), change "scripting flag" to an enum for clarity.
Currently per spec, #update-the-navigation-api-entries-for-a-same-document-navigation
will be called in different order to the #wait-for-all navigation handler
list depending on if the navigation is intercepted or not. This is not
ideal, but even more so, in case of a "traverse" navigation, the
callback passed to the #wait-for-all and the might be called before
the call to #update-the-navigation-api-entries-for-a-same-document-navigation
has happened.

This means that we'll run the finish steps with the wrong session
history entry.

Since all same document navigations, intercepted or otherwise, eventually
call #update-the-navigation-api-entries-for-a-same-document-navigation
we can ensure that we never run the navigation handlers with bad state.

This patch also reverts the patch that introduced always having a
method tracker, since that was intended to solve this issue but
failed doing so.

Fixes whatwg#12222, fixes whatwg#12165. Reverts whatwg#11814.
* Markup: For some `data-x="attr-input-{max,min}"`, change `attr` to `concept`
* Punctuation: Insert a couple periods
* Punctuation: Change colon to period
…attribute

Specify support for the loading attribute for the video element and audio element using similar conventions to img and iframe, where the attribute already has precedent. Loading has possible values of eager and lazy. When a media element's loading attribute value is lazy, loading of any video or poster image data, as well as autoplay playback, will defer until layout is known and the video is in the viewport.

Fixes whatwg#10376
Fixes whatwg#6636
Key changes:
- Rename 'no-memory' token to 'nomemory' (unhyphenated, matching explainer)
- Add 'nowrap' modifier token for explicitly disabling wrapping
- Add default modifiers per behavior token (toolbar→inline,
  tablist→inline wrap, menu→block wrap, menubar→inline wrap)
- Add default modifiers column to behavior tokens table
- Add text explaining how default modifiers work and interact
  with explicit modifiers
- Update ARIA Role Inference to document <button> child role inference
  eligibility (buttons are the most common composite widget item)
- Add note that aria-orientation is not inferred from inline/block
- Add note about reading-flow CSS property interaction with both
  sequential and directional navigation
- Update directional navigation algorithm to reference effective
  modifiers (including defaults)
- Update wrap check in navigation algorithm to account for nowrap
  and default modifiers
- Replace toolbar example with proper tablist example showing
  default modifiers, focusgroupstart, child role inference, and
  tab panel association
- Add menubar/menu nested focusgroup example demonstrating
  independent nested focusgroups with default axis/wrap behavior

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Reword key conflict element definition to emphasize native/built-in
  arrow key behavior (UA-determined), not author-scripted handlers
- Add note with author guidance for scripted key conflicts: use
  focusgroup='none', limit axis, or activation/escape pattern
- Fix scrolling conflict scenario to reference key conflict escape
  behavior and clarify that only focusable scrollable regions
  (UA-determined) are affected

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment