Skip to content

feat(DropdownMenu)!: arrows hand focus between a header field and the rows - #7532

Open
vjeux wants to merge 2 commits into
facebook:mainfrom
vjeux:header-field-arrows
Open

vjeux wants to merge 2 commits into
facebook:mainfrom
vjeux:header-field-arrows

Conversation

@vjeux

@vjeux vjeux commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

User need

A menu with a filter field in its header (#7344) is used by typing, then picking. From the field only Tab reaches the rows, stopping on the menu as a whole, and no arrow leads back. A combobox moves between its input and list with ArrowDown and ArrowUp; keyboard users expect the same here.

Problem and solution fit

In the popover, with a single-line text field in header, ArrowDown in the field moves to the first enabled row, and ArrowUp on that row then returns to the field instead of wrapping to the last row; before any hand-off, ArrowUp wraps as before. The field keeps every key whose meaning it owns. The bottom sheet and a drilled-in sub-menu view hand no arrows on.

Current specification

component:DropdownMenu (draft, @cixzhang) gains FR21 and DEC-14, both proposed and pending owner review, as a named exception to spec:AST-020 FR15 that AR5 names; FR15 and DEC-8 point to it where they say a region keeps its own keys. Other proposals in open pull requests: #7319 FR18/DEC-11, #7352 FR19/DEC-12, #7541 FR22/DEC-15; #7839 and #7840 amend FR20.

Public delta and caller burden

  • ArrowDown in a header input of type text, search, email, url, tel or password moves focus to the first enabled row; the key is handled only when focus moves.
  • ArrowUp on the first enabled row moves focus back to the field ArrowDown left in this open; until then, it wraps.
  • Kept: a modified arrow (text selection), an IME composition key, an ArrowDown the field already handled (default prevented), and every key in a number, range, multi-line, button, combobox or spinbutton (NumberInput) control or an input with a list.
  • No new props. Breaking under spec:AST-017 FR1: 0.7 documents that a header "keeps its own keys and presses", so a field whose ArrowDown handler leaves the default now also hands focus on. Migration: prevent that default; no codemod, as the reliance is not visible in source. [breaking] waits for a planned minor; an opt-in prop would keep it a patch, the owner's call.

Design and alternatives

Rejected: moving to the rows from any header control, which takes arrows from controls that use them; and keeping the wrap on the first row, which leaves the field unreachable by arrow.

Writing rubric results

  • R1 narration: none.
  • R2 research in a record: none.
  • R3 evidence naming a change: none.
  • R4 rejected alternatives over one line or outside a decision: none.
  • R5 pull request or issue references: none.
  • R6 ruled open questions listing options: none.

Evidence

See Testing.

Scope

  • One capability is added.
  • Unrelated fixes, cleanup, and policy changes were removed or split.
  • Consumer docs, focused tests, and a changeset ship with the feature.
  • Public text and artifacts contain no internal Meta context.

Testing

  • Review round (41a2ee9, rebased onto main be42333): the record's Compatibility and migration section said the released default was preserved and the change was additive documentation; it now says the released default is not preserved (with proposed FR21 a header text field hands ArrowDown to the rows), names the change as breaking under spec:AST-017 FR1, and gives proposed DEC-14's migration (a field that needs ArrowDown prevents its default). Record wording only. DropdownMenu, NumberInput, TimeInput and doc-prop suites: 762 tests; header arrows and header-and-footer Chromium specs: 12; typecheck, strict eslint, check:knowledge, the rest of check:repo, Storybook build: clean; check:changesets rejects [breaking] while main declares patch 0.7.3.

  • Rebased onto main cab6e90, no conflicts or changes: main's new pr-a11y TopNav step runs a spec file the previous head predates. DropdownMenu, NumberInput, TimeInput and doc-prop suites: 762 tests; typecheck, check:knowledge: clean.

  • Rebased onto main b7860bc after feat(DropdownMenuSubMenu): header and footer around a sub-menu's rows #7530 merged, as one commit; the record and DropdownMenu.tsx conflicts keep both sides. pr-a11y gets a "Run DropdownMenu header field arrows contract" step for MenuHeaderArrows.a11y.chromium.spec.ts. DropdownMenu, ContextMenu, MoreMenu, NumberInput, TimeInput and doc-prop suites: 849 tests; header arrows and header-and-footer Chromium specs: 12; typecheck, strict eslint, check:knowledge, the rest of check:repo, Storybook build: clean; check:changesets rejects [breaking] while main declares patch 0.7.3.

  • Review round (rebased onto main 863e167): DEC-14 records, as accepted, what a screen-reader user perceives of the hand-off: the field stays a plain textbox or searchbox with no relation to the menu, and a Down Arrow pressed to re-read a one-line field now moves to the rows, while the menu leaves Up Arrow and the screen reader's own reading commands to the field. Record wording only. DropdownMenu and doc-prop suites: 313 tests; header arrows and header-and-footer Chromium specs: 12; typecheck, strict eslint, check:knowledge, the rest of check:repo, Storybook build: clean; check:changesets rejects [breaking] as before.

  • Rebased onto main d0f9afe, no conflicts or changes. The previous head's pr-a11y and smoke-test reds came from CI: main's fix(Tooltip): keep the tooltip open when the pointer crosses onto it in one step #7802 added a pr-a11y step whose spec file the older head lacked, and jsdelivr was still propagating core@0.7.2. DropdownMenu, NumberInput, TimeInput, docProp* suites: 740 tests; typecheck, check:knowledge: clean.

  • Review round: ArrowUp on the first row returns only to the field ArrowDown left for the rows in this open, and otherwise wraps as FR12 states, so it never lands in a TimeInput before a hand-off. New cases (wrap before a hand-off, past a header TimeInput, after a reopen) fail on the previous head. The Accessibility contract's opening names FR21's hand-off, and the header doc says a field that prevents ArrowDown's default keeps it. The Chromium spec reaches the field with Shift+Tab and checks the wrap first. DropdownMenu, ContextMenu, MoreMenu, NumberInput, TimeInput and doc-prop suites: 826 tests; header arrows and header-and-footer Chromium specs: 12; typecheck, strict eslint, check:knowledge, the rest of check:repo, Storybook build: clean; check:changesets rejects [breaking] as before.

  • Review round (rebased onto main 2c3ed99): ArrowUp on the first row returns to the field ArrowDown last left, and a field with a role of its own (a NumberInput spinbutton) keeps its arrows; three new cases (a header NumberInput, a time field after the filter, two plain fields) fail on the previous head. AR5, FR21 and DEC-14 name the hand-off as DropdownMenu's named exception under spec:AST-020/FR15, and the Header And Footer story says the field hands its arrows on. The rule takes FR21 and DEC-14 so open proposals in this record stay distinct. DropdownMenu, ContextMenu, MoreMenu, NumberInput, TimeInput and doc-prop suites: 824 tests; header arrows and header-and-footer Chromium specs: 12; typecheck, strict eslint, check:knowledge, the rest of check:repo, Storybook build: clean. check:changesets still rejects [breaking] while main declares patch 0.7.2.

  • Rebased onto main 577a62e after refactor(DropdownMenu): the header and footer Tab walk moves to a module of its own #7737 moved the header and footer Tab walk into menuRegionStops.ts: the hand-off now imports tabbablesIn and focusRegionControl from there instead of keeping its own copies, unchanged. DropdownMenu, ContextMenu, MoreMenu and doc-prop suites: 394 tests; the header arrows and header-and-footer Chromium specs: 12; typecheck, eslint (strict), check:knowledge, the rest of check:repo, Storybook build: clean. check:changesets still rejects the [breaking] changeset while main declares patch 0.7.2, as before.

  • Review round: FR18, the header doc and the changeset are scoped to the popover. Two new guards pass on main and here: the bottom sheet's header field keeps ArrowDown, and while a sub-menu view is drilled in the field keeps ArrowDown and Back keeps the wrap. check:changesets fails by design ([breaking] while main plans 0.7.2), so the commit used --no-verify after lint-staged and every other check:repo step passed by hand. DropdownMenu, ContextMenu, MoreMenu and doc-prop suites (394 tests), the header Chromium specs (12), core typecheck, ESLint strict, check:knowledge, Storybook build: green.

  • Rebased onto main (22c592a) now that fix(DropdownMenu): a popover with a header or footer is a modal dialog, and Tab wraps #7515 has merged, and retargeted to main. The rule is proposed FR18 and the decision DEC-11, since main took FR17.

  • DropdownMenu.test.tsx "header field arrows" suite, 9 cases (7 plus the 2 guards): ArrowDown from the field; a field that already handled ArrowDown, a combobox, and an input with a list keep it; ArrowUp from the first row and from another row; a disabled first row both ways; several header controls; Shift, IME, number and multi-line controls keep the key; no text field means the wrap is unchanged. On main 4 fail and the 3 keep-the-key guards pass; the combobox case also fails at the previous head. All 7 pass here.

  • __tests__/MenuHeaderArrows.a11y.chromium.spec.ts against the existing "Header And Footer" story, real Chromium and keyboard: a keyboard open, ArrowUp to the field, typing a filter, ArrowDown to the first filtered row, and ArrowUp back with the value and caret intact; Shift with an arrow stays in the field. Both fail against a main build and pass here.

  • DropdownMenu, ContextMenu, Typeahead and doc-prop suites (487 tests), plus every DropdownMenu Chromium spec (59): green. Core typecheck, lint:strict, check:knowledge, Storybook build: clean.

  • Not run on the iOS simulator: it cannot deliver hardware arrow keys to web content, and touch has no arrows.

@vercel

vercel Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
astryx Ready Ready Preview Oct 22, 2026 8:00am UTC

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Oct 14, 2026
@astracat-bot

astracat-bot Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
❓ Needs maintainer input (for maintainers only) Oct 22, 2026, 8:33 AM UTC

@astracat-bot astracat-bot Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval is waiting on a maintainer decision: arrow keys between the header text field and the rows move focus between separately focusable parts, which AST-020 FR15 allows only as a named exception, so the DropdownMenu owner needs to accept or decline proposed FR17 and DEC-12 as that exception. Independently, ArrowDown should be left to a header field that already handled it: today a combobox such as Typeahead in header acts on the key and then loses focus to the first row, and skipping events whose default is already prevented, plus a regression case, would cover it. Please also retarget to main, where FR17 already names another requirement, and renumber the new one.

[Automated review]

Comment on lines +1306 to +1312
if (
isPlainArrow(e, 'ArrowDown') &&
isTextEntryField(e.target) &&
headerRef.current?.contains(e.target) === true &&
focusFirst()
) {
e.preventDefault();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This check never looks at whether the field already handled ArrowDown. A combobox in header (Typeahead renders <input type="text" role="combobox"> and only calls preventDefault()) acts on the key and then loses focus to the first row, so its suggestions can't be reached by keyboard. Something like this lets the field's own handling win:

const field = e.target;
if (
  !e.defaultPrevented &&
  isPlainArrow(e, 'ArrowDown') &&
  isTextEntryField(field) &&
  field.getAttribute('role') !== 'combobox' &&
  !field.hasAttribute('list') &&
  headerRef.current?.contains(field) === true &&
  focusFirst()
) {
  e.preventDefault();
}

A "header field arrows" case with a combobox field that handles ArrowDown would pin it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 795b8c6: ArrowDown moves on only when its default is not already prevented, and a field with a list of its own (role="combobox", or an input with a list) is not treated as the menu's input in either direction. New case "leaves ArrowDown to a header field that handles it or has a list of its own" fails at the previous head.

@github-actions
github-actions Bot deleted the branch facebook:dropdown-menu-regions-dialog October 15, 2026 06:22
@vjeux
vjeux changed the base branch from dropdown-menu-regions-dialog to main October 20, 2026 14:26
@vjeux
vjeux force-pushed the header-field-arrows branch from 2d09320 to 795b8c6 Compare October 20, 2026 14:26
@vjeux

vjeux commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main and retargeted to it now that #7515 has merged. The rule is proposed FR18 and the decision DEC-11, since main took FR17. A header field that already handled ArrowDown, or has a list of its own (a combobox, an input with a list), keeps the key.

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR

🧪 Sandbox Preview

View Sandbox for this PR

No new or modified components detected.

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@astryxdesign/core N/A 4.9KB 1.2KB

Accessibility Audit

Status: No accessibility violations detected.

Visual Regression

46 of 486 shot(s) changed.

A change here is a question, not a failure: check whether the after is the
picture you intended. Record that review on the PR. Baseline maintenance is an
explicit dispatch of CI; this report never rewrites the baseline or adds a release gate.

component story theme mode pixels
Selector Indicator Space Bottom Sheet Narrow End RTL neutral light 753,933
Selector Indicator Space Bottom Sheet Wide Start neutral light 740,072
Chat Full AI Chat probe light 230,823
Chat Full AI Chat probe dark 229,805
RichTextEditor Markdown parity: side by side probe dark 94,866
RichTextEditor Markdown parity: side by side probe light 89,762
Collapsible Dividers probe dark 66,445
Collapsible Dividers probe light 66,445
Chat Default neutral dark 36,304
Chat Default neutral light 35,767
Chat Empty State probe light 23,531
Chat Empty State probe dark 22,622
ChatAutoScroll Scroll Behavior Comparison neutral dark 15,378
ChatAutoScroll Scroll Behavior Comparison neutral light 14,107
Chat With Attachments probe light 13,406
Chat With Attachments probe dark 11,232
ProgressBar With Target Mark probe dark 7,895
ProgressBar With Target Mark probe light 7,895
Markdown Default neutral dark 7,573
Markdown Default neutral light 7,566

and 26 more.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval is waiting on a maintainer decision: arrow keys between a header text field and the menu rows move focus between separately focusable parts, which AST-020 FR15 allows only as a named exception, so a maintainer (the DropdownMenu owner) needs to accept or decline proposed FR18 and DEC-11 as the governing spec for that exception. If it is accepted, please also:

  • scope FR18, the header doc sentence and the changeset to the pointer menu's top-level rows, or extend the arrows, since the bottom sheet and a drilled-in sub-menu view do not get them today;
  • amend FR15 and DEC-8, which still say a region keeps its own keys, and confirm that a patch fits the narrowed "keeps its own keys" promise.

The earlier header-combobox and renumbering findings are fixed.

[Automated review]

| FR15 | With `header` or `footer`, the pointer popover is a `role="dialog"` with `aria-modal="true"`, named like the menu, holding the header, then the `role="menu"` element, then the footer; the menu element holds only its rows. The trigger says `aria-haspopup="dialog"` and its `aria-controls` names the popover that holds the dialog. A region keeps its own keys and presses: neither the menu's key handling nor its press model claims an event that begins there. The menu is one Tab stop between the regions. Tab and Shift+Tab move through the header's controls, the menu, then the footer's controls, and wrap at either end; a control that is hidden, or under a hidden ancestor within its region, is not a stop. From a row, or a row of an open sub-menu, Tab and Shift+Tab close every open flyout and continue from the menu's stop. With no other stop, focus stays in the menu. Escape closes from anywhere in the popover, and focus returns to the trigger. The bottom sheet, already a dialog, shows the header above the actions and the footer below them. Without either prop, the menu renders and behaves exactly as it does without them: no dialog, `aria-haspopup="menu"`, and Tab closes the menu. | DEC-8, DEC-10, docs, and tests | Proposed; awaiting owner approval |
| FR16 | `DropdownMenuCheckboxItem` MUST expose one `menuitemcheckbox` row whose `aria-checked` equals its controlled value; enabled activation reports `!value`, stays open by default, and composes consumer click and pointer-move handlers with owned activation and hover focus. Disabled activation calls no consumer activation handler. | Released subcomponent API; `architecture:public-component-api/INV5–INV8`; `DropdownMenuSelectable.test.tsx` | Verified current behavior; consumer handlers are preserved |
| FR17 | Disabled menu rows SHOULD remain keyboard-discoverable while activation stays blocked. Current shared `useListFocus` deliberately skips every `aria-disabled` row, including checkbox items. | WAI-ARIA Menu pattern; current shared navigation source/tests | Objective mismatch; shared mechanism remains undecided in OQ1 |
| FR18 | With a single-line text field in `header` (an `input` of type `text`, `search`, `email`, `url`, `tel` or `password`), ArrowDown in that field moves focus to the menu's first enabled row, as from a combobox's input to its list, and ArrowUp on the first enabled row moves focus back to the last such field in the header instead of wrapping to the last row. Both keys are handled in full only when focus moves. An arrow with a modifier, a key inside an IME composition, an ArrowDown the field already handled (its default prevented), and any key in a control whose arrows mean something of their own (a number, a range, a multi-line text, a button, a combobox, an input with a `list`) keep their native behavior. The menu's other keys (FR12) are unchanged, and without such a field ArrowUp on the first row wraps as FR12 states. | Proposed DEC-11; FR12; FR15 | Proposed; verified in jsdom and Chromium, pending owner review |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

FR18 states the arrows for any single-line text field in header, but only the pointer menu's top-level rows run them: the bottom sheet renders header without a key handler (DropdownMenu.tsx:968-970), and in a drilled-in sub-menu view ArrowUp on the Back row wraps to the last drilled row. If FR18 is accepted, scope this row, the header doc sentence and the changeset to the pointer menu's top-level rows (or extend both handlers), and amend FR15 (line 119) and DEC-8, which still say a region keeps its own keys.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Scoped in e7e9667. FR18 now opens "In the pointer popover" and says the bottom sheet and a drilled-in sub-menu view hand no arrows between the field and the rows. DEC-11 gives the reason: the sheet's actions are a list of their own, and a drilled-in view's field filters rows that are out of view. Two guards pin it, the bottom sheet's field keeping ArrowDown, and a drilled-in view where the field keeps ArrowDown and Back keeps the wrap; the verification row lists both. FR15 now says a region keeps its own keys "except for the arrows of proposed FR18". DEC-8 says proposed DEC-11 hands on one key, a header text field's ArrowDown.

type: 'ReactNode',
description:
'Content above the rows and outside the menu itself — a filter field, a toggle. A menu holds only its rows, so a control that is not a row goes here or in `footer`, never among the rows. It keeps its own keys and presses. With a header or footer the popover is a modal dialog around the menu: Tab and Shift+Tab move through the header, the menu and the footer and wrap at either end, and Escape closes. The bottom sheet shows it above the actions.',
'Content above the rows and outside the menu itself — a filter field, a toggle. A menu holds only its rows, so a control that is not a row goes here or in `footer`, never among the rows. It keeps its own keys and presses, except that ArrowDown in a single-line text field there moves to the first row, and ArrowUp on the first row returns to it. With a header or footer the popover is a modal dialog around the menu: Tab and Shift+Tab move through the header, the menu and the footer and wrap at either end, and Escape closes. The bottom sheet shows it above the actions.',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This sentence promises the arrows wherever header holds a text field, including the bottom sheet the last sentence mentions; with presentation="bottom-sheet" ArrowDown in the field stays put. Naming the pointer menu here would match what the component does.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in e7e9667: the sentence now says "in the popover", and the changeset names the bottom sheet and a drilled-in sub-menu view as keeping their keys.

@vjeux vjeux changed the title feat(DropdownMenu): arrows hand focus between a header field and the rows feat(DropdownMenu)!: arrows hand focus between a header field and the rows Oct 20, 2026
@vjeux

vjeux commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

On the classification: a patch does not fit. Under spec:AST-017 FR1, 0.7.0 shipped the header doc's "It keeps its own keys and presses". A header field whose own ArrowDown handler leaves the default would now also hand focus to the rows, and keeping its key takes a source change (prevent that default). So e7e9667 makes the changeset [breaking] (minor on 0.x) and names that migration. There is no codemod, since the reliance is not visible in source. The title now carries !. check:changesets rejects it while main plans 0.7.2, as designed, so this waits for a planned minor.

If the owner would rather ship it in a patch, the compatible route is opt-in, through a prop or a marker on the field, with the hand-off staying off by default. That is an API choice for the record's owner, together with FR18 and DEC-11.

@astracat-bot astracat-bot Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval is waiting on a maintainer decision: arrow keys that move focus between a header text field and the menu rows join two separately focusable parts, which AST-020 FR15 allows only as a named exception, so the DropdownMenu owner needs to approve or decline proposed FR18 and DEC-11 as the governing spec for that exception, on by default in the next planned minor or behind an opt-in. If it is approved, the ArrowUp target needs to skip header steppers: NumberInput renders <input type="text" role="spinbutton"> and TimeInput a plain text input, so ArrowUp on the first row enters them and the ArrowDown pressed to return steps the value (100 to 99 in Chromium), which a header NumberInput and TimeInput case would pin. Please also name FR18 as that exception in the record (AR5, FR18 and DEC-11, the way AR4 and DEC-9 do for the trigger's arrow keys) and update the Header And Footer story description, which still says the field keeps its own keys.

[Automated review]

Comment thread packages/core/src/DropdownMenu/DropdownMenu.spec.md Outdated
@vjeux

vjeux commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main (577a62e) after #7737 moved the header and footer Tab walk into menuRegionStops.ts. The hand-off now imports tabbablesIn and focusRegionControl from that module instead of keeping its own copies, which is why #7737 left them exported. Behavior is unchanged: 394 unit tests and 12 Chromium cases pass. check:changesets still rejects the [breaking] changeset while main declares patch 0.7.2.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval is waiting on a maintainer decision: arrow keys that move focus between a header text field and the menu rows join two separately focusable parts, which AST-020 FR15 allows only as a named exception, so the DropdownMenu owner needs to approve or decline proposed FR18 and DEC-11 as the governing spec for it, and choose between on by default in the next planned minor (main declares 0.7.2, so check:changesets refuses the [breaking] Changeset until then) or an opt-in. These points from the last round still apply after the rebase and need fixing if it is approved:

  • A header NumberInput (<input type="text" role="spinbutton">) or TimeInput becomes the ArrowUp target, so the ArrowDown pressed to return to the rows steps its value instead (100 to 99 in Chromium); skipping role="spinbutton", preferring the field ArrowDown last left, and header NumberInput and TimeInput cases would cover it.
  • FR18, DEC-11 and AR5 should name the hand-off as DropdownMenu's named exception under spec:AST-020/FR15, the way AR4 and DEC-9 do for the trigger's arrow keys.
  • The Header And Footer story description still says the field keeps its own keys.

[Automated review]

) &&
// A field with a list of its own (a combobox, or an input with a
// datalist) keeps its arrows for that list.
element.getAttribute('role') !== 'combobox' &&

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This is the only gate on the ArrowUp target (line 1286), and it lets a stepper through: NumberInput renders <input type="text" role="spinbutton"> and TimeInput a plain <input type="text">, and both step on ArrowDown. With a filter field and then one of them in header, ArrowUp on the first row lands in the stepper, and the ArrowDown pressed to go back changes its value (100 to 99 in Chromium) while focus stays. Skipping role="spinbutton" here, preferring the field ArrowDown last left (which also covers TimeInput), and adding header NumberInput and TimeInput cases would fix it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 62303f3, rebased onto main 2c3ed99.

  • A field with a role other than textbox or searchbox keeps its arrows, so NumberInput (role spinbutton) is never the ArrowUp target.
  • ArrowUp on the first row returns to the field ArrowDown last left, which passes over a later time field; otherwise it goes to the last text field.

Three new cases fail on the previous head:

  • a header NumberInput after the filter;
  • a TimeInput after the filter;
  • two plain fields, where ArrowDown left from the first.

One gap remains: before any ArrowDown hand-off, a TimeInput that is the header's last text field is still the ArrowUp target, because nothing in its markup says its arrows step.

vjeux added a commit to vjeux/astryx that referenced this pull request Oct 21, 2026
Five open pull requests propose rules in this record: facebook#7319 (FR18, DEC-11), facebook#7352 (FR19, DEC-12), facebook#7530 (FR20, AR7, DEC-13), facebook#7532 (FR21, DEC-14) and facebook#7541 (FR22, DEC-15). Each takes its own number, so none changes when another merges first. Record wording only.
vjeux added a commit to vjeux/astryx that referenced this pull request Oct 21, 2026
Five open pull requests propose rules in this record: facebook#7319 (FR18, DEC-11), facebook#7352 (FR19, DEC-12), facebook#7530 (FR20, AR7, DEC-13), facebook#7532 (FR21, DEC-14) and facebook#7541 (FR22, DEC-15). Each takes its own number, so none changes when another merges first. Record wording only.
@vjeux
vjeux force-pushed the header-field-arrows branch from fabcf58 to 62303f3 Compare October 21, 2026 15:55
vjeux added a commit to vjeux/astryx that referenced this pull request Oct 21, 2026
Five open pull requests propose rules in this record: facebook#7319 (FR18, DEC-11), facebook#7352 (FR19, DEC-12), facebook#7530 (FR20, AR7, DEC-13), facebook#7532 (FR21, DEC-14) and facebook#7541 (FR22, DEC-15). Each takes its own number, so none changes when another merges first. Record wording only.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval is waiting on a maintainer decision: arrow keys that move focus between a header text field and the menu rows join two separately focusable parts, which spec:AST-020 FR15 allows only as a named exception, so the DropdownMenu owner needs to approve or decline proposed FR21 and DEC-14 as the governing spec for it, and choose between on by default in a planned minor (main declares 0.7.2, so check:changesets refuses the [breaking] Changeset until then) or an opt-in. The TimeInput, Accessibility-contract and header doc points from the last round are fixed, and no other defect turned up. One point for the record while it waits:

  • FR21 says where focus moves but not what a screen-reader user perceives: the field keeps its plain textbox or searchbox role with no link to the menu, so a Down Arrow pressed to re-read the field now leaves it; stating that, or recording it as accepted, would help the owner decide.

[Automated review]

vjeux added a commit to vjeux/astryx that referenced this pull request Oct 21, 2026
Five open pull requests propose rules in this record: facebook#7319 (FR18, DEC-11), facebook#7352 (FR19, DEC-12), facebook#7530 (FR20, AR7, DEC-13), facebook#7532 (FR21, DEC-14) and facebook#7541 (FR22, DEC-15). Each takes its own number, so none changes when another merges first. Record wording only.
vjeux added a commit to vjeux/astryx that referenced this pull request Oct 21, 2026
Five open pull requests propose rules in this record: facebook#7319 (FR18, DEC-11), facebook#7352 (FR19, DEC-12), facebook#7530 (FR20, AR7, DEC-13), facebook#7532 (FR21, DEC-14) and facebook#7541 (FR22, DEC-15). Each takes its own number, so none changes when another merges first. Record wording only.
vjeux added a commit to vjeux/astryx that referenced this pull request Oct 21, 2026
Five open pull requests propose rules in this record: facebook#7319 (FR18, DEC-11), facebook#7352 (FR19, DEC-12), facebook#7530 (FR20, AR7, DEC-13), facebook#7532 (FR21, DEC-14) and facebook#7541 (FR22, DEC-15). Each takes its own number, so none changes when another merges first. Record wording only.
@vjeux
vjeux force-pushed the header-field-arrows branch from adb3358 to ece5f14 Compare October 21, 2026 18:08

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval is waiting on a maintainer decision: arrow keys that move focus between a header text field and the menu rows join two separately focusable parts, which spec:AST-020 FR15 allows only as a named exception, so the DropdownMenu owner needs to approve or decline proposed FR21 and DEC-14 as the governing spec for it, and choose between on by default in a planned minor (main declares 0.7.2, so check:changesets refuses the [breaking] Changeset until then) or an opt-in. No defect turned up, so nothing is needed from you until that decision lands; if the owner picks the opt-in, the hand-off will need that new surface and a compatible Changeset. One point the owner may want FR21 to state is what a screen-reader user perceives: the field keeps its plain textbox role with nothing tying it to the menu, so a Down Arrow pressed to re-read the field now leaves it.

[Automated review]

vjeux added a commit to vjeux/astryx that referenced this pull request Oct 21, 2026
Five open pull requests propose rules in this record: facebook#7319 (FR18, DEC-11), facebook#7352 (FR19, DEC-12), facebook#7530 (FR20, AR7, DEC-13), facebook#7532 (FR21, DEC-14) and facebook#7541 (FR22, DEC-15). Each takes its own number, so none changes when another merges first. Record wording only.
@vjeux
vjeux force-pushed the header-field-arrows branch from ece5f14 to 504b40b Compare October 21, 2026 19:04
@vjeux

vjeux commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

On what a screen-reader user perceives of the hand-off: DEC-14 now records it as accepted (504b40b). The field stays a plain textbox or searchbox with no relation to the menu, and the first row is heard as focus moves to it. A Down Arrow pressed to re-read a one-line field, as some screen readers allow in focus mode, now moves to the rows; the menu leaves Up Arrow and the screen reader's own reading commands to the field, and a field that needs Down Arrow keeps it by preventing the default. Record wording only.

vjeux added a commit to vjeux/astryx that referenced this pull request Oct 21, 2026
Five open pull requests propose rules in this record: facebook#7319 (FR18, DEC-11), facebook#7352 (FR19, DEC-12), facebook#7530 (FR20, AR7, DEC-13), facebook#7532 (FR21, DEC-14) and facebook#7541 (FR22, DEC-15). Each takes its own number, so none changes when another merges first. Record wording only.
vjeux added a commit to vjeux/astryx that referenced this pull request Oct 21, 2026
Five open pull requests propose rules in this record: facebook#7319 (FR18, DEC-11), facebook#7352 (FR19, DEC-12), facebook#7530 (FR20, AR7, DEC-13), facebook#7532 (FR21, DEC-14) and facebook#7541 (FR22, DEC-15). Each takes its own number, so none changes when another merges first. Record wording only.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval is waiting on a maintainer decision: arrow keys that move focus between a header text field and the menu rows join two separately focusable parts, which spec:AST-020 FR15 allows only as a named exception in the owning record, so the DropdownMenu owner needs to approve or decline proposed FR21 and DEC-14 as the governing spec for that exception, and choose between on by default in a planned minor (main declares 0.7.2, so check:changesets refuses the [breaking] Changeset until then) or an opt-in. No defect turned up on this revision, so nothing is needed from you until that decision lands; if the owner picks the opt-in, the hand-off will need that new surface and a compatible Changeset.

[Automated review]

vjeux added a commit to vjeux/astryx that referenced this pull request Oct 21, 2026
Five open pull requests propose rules in this record: facebook#7319 (FR18, DEC-11), facebook#7352 (FR19, DEC-12), facebook#7530 (FR20, AR7, DEC-13), facebook#7532 (FR21, DEC-14) and facebook#7541 (FR22, DEC-15). Each takes its own number, so none changes when another merges first. Record wording only.
vjeux added a commit to vjeux/astryx that referenced this pull request Oct 21, 2026
Five open pull requests propose rules in this record: facebook#7319 (FR18, DEC-11), facebook#7352 (FR19, DEC-12), facebook#7530 (FR20, AR7, DEC-13), facebook#7532 (FR21, DEC-14) and facebook#7541 (FR22, DEC-15). Each takes its own number, so none changes when another merges first. Record wording only.
cixzhang pushed a commit that referenced this pull request Oct 21, 2026
…#7530)

> Data items' `header` and `footer`, and the bottom sheet's level regions, follow once this merges.

## User need

A sub-menu picking from a long list needs a filter field above its rows, often a "Create" button below. #7344 gave the root menu `header` and `footer`; a sub-menu has neither, so the field goes among the rows (DEC-8 forbids it) or the picker leaves the menu.

## Problem and solution fit

`DropdownMenuSubMenu` takes `header` and `footer` under the root's rules (DEC-8, DEC-10). With either, the sub-menu's surface (the flyout, or the drilled-in view on a phone) is a modal dialog named by its row, holding the header, the sub-menu's `role="menu"` with rows only, and the footer. A flyout renders inside its parent menu, so `DropdownMenu` renders a host beside its menu for the dialog. A drilled-in view with regions replaces the root's menu and regions until popped, by a style rule that reads the host.

```tsx
<DropdownMenuSubMenu label="Labels" header={<TextInput label="Filter labels" … />} footer={<Button label="Create label" … />}>
  {visibleLabelRows}
</DropdownMenuSubMenu>
```

## Current specification

`component:DropdownMenu` (draft) gains a concept row, FR20, AR7 and DEC-13, all proposed and pending owner review. Other proposals in open pull requests: #7319 FR18/DEC-11, #7352 FR19/DEC-12, #7532 FR21/DEC-14, #7541 FR22/DEC-15. `module:DropdownMenu/useMenuPress` (current) gains a proposed ORD1a: a press released on a row of that dialog's menu acts, as FR1 requires for any flyout; a picker placed in its header or footer stays its own press root.

## Public delta and caller burden

- `header` and `footer` on `DropdownMenuSubMenu`.
- With either, the row says `aria-haspopup="dialog"`; Tab walks header, rows as one stop, footer, and wraps; an Escape nothing inside handled returns to the row; a pointer leaving the flyout keeps it open until focus leaves. Rendered beside the root's menu, such a flyout closes with the flyout holding its row.
- Phone drill-in: a shown view follows its regions and caps at the root's `menuMaxHeight`.
- `ContextMenu` renders no host: there the sub-menu shows its rows alone and warns in development; parity follows once this merges.
- Without them, nothing changes.

## Design and alternatives

Rejected: regions inside the flyout (inside the parent menu); a separate `DropdownMenu` per level; closing on pointer-leave, losing typed text. A drilled-in view's header sits above Back.

## Writing rubric results

- R1 narration: none.
- R2 research in a record: none.
- R3 evidence naming a change: none.
- R4 rejected alternatives over one line or outside a decision: none.
- R5 pull request or issue references: none.
- R6 ruled open questions listing options: none.

## Evidence

See Testing.

## Scope

- [x] One capability is added.
- [x] Unrelated fixes, cleanup, and policy changes were removed or split.
- [x] Consumer docs, focused tests, a story and a changeset ship with the feature.
- [x] Public text and artifacts contain no internal Meta context.

## Testing

Review round 8 (rebased onto `main` b74cf21): `pr-a11y` gets a "Run DropdownMenu sub-menu header and footer contract" step beside "Run DropdownMenu header and footer contract". It runs `SubMenuHeaderFooter.a11y.chromium.spec.ts` with `--project chromium`, so FR20's real-engine checks gate every head. That exact command passes locally against a Storybook built from this head (6 cases). 15 files, +1867/−121 (1,988 lines). DropdownMenu, ContextMenu, Layer, MoreMenu, RadioList, `useMenuPress` and doc-prop suites: 739 tests; header and footer Chromium specs: 16; `.github/scripts` workflow tests: 100; typecheck, `lint:strict`, `check:knowledge`, Storybook build: clean.

Review round 7 (rebased onto `main` 863e167): `surfaceHost`, `surfaceOwnerId` and `menuMaxHeight` leave the exported `DropdownMenuContextValue` for `DropdownMenuSurfaceContext`, which the package does not export, layer-scoped and re-provided by each flyout as the menu context is; the public type matches `main`. A new `DropdownMenuContext.public.test.ts` pins its four members (it fails typecheck with the three back) and checks the internal context is not exported. Data-mode parity (data items' `header` and `footer`, `renderDropdownItems`, the bottom sheet's warning and their tests) moves to the follow-up, and the three pointer-leave cases share one setup: 14 files, +1856/−121 (1,977 lines). DropdownMenu, ContextMenu, Layer, MoreMenu, RadioList, `useMenuPress` and doc-prop suites: 739 tests; header and footer Chromium specs: 16; typecheck, `lint:strict` (no warnings), `check:knowledge`, Storybook build: clean.

Rebased onto `main` d0f9afe, no conflicts or changes. The previous head's `pr-a11y` and `smoke-test` reds came from CI: main's #7802 added a `pr-a11y` step whose spec file the older head lacked, and jsdelivr was still propagating core@0.7.2. DropdownMenu, ContextMenu, RadioList, docProp* suites: 477 tests; typecheck, `check:knowledge`: clean.

Review round 6: a flyout the pointer has left now decides that focus left once the move has completed, so an arrow key in a header radio group, where the browser moves focus itself, no longer closes it. A jsdom case replays the browser's order (focusout, a microtask checkpoint, focusin) and fails on the previous head; a Chromium case on the new "Submenu / header with a choice" story presses ArrowDown after the pointer leaves, and fails against a Storybook built from the previous head, where the flyout closes. DropdownMenu, ContextMenu, Layer, MoreMenu, RadioList, `useMenuPress` and doc-prop suites: 741 tests; header and footer Chromium specs: 16; typecheck, `lint:strict`, `check:knowledge`, Storybook build: clean.

Review round 5 (rebased onto `main` 2c3ed99; the earlier `test` and `test-node` reds were `main`'s own, a PostCSS fixture that #7797 fixed): an Escape a control in a region already handled (a header menu closing, a field clearing itself) closes nothing more, and the new case fails on the previous head. The contract takes FR20, AR7 and DEC-13 so open proposals in this record stay distinct. DropdownMenu, ContextMenu, Layer, MoreMenu, `useMenuPress` and doc-prop suites: 646 tests; header and footer Chromium specs: 15; typecheck, `lint:strict`, `check:knowledge`, Storybook build: clean.

Rebased onto `main` 577a62e after #7737 merged: one commit, 15 files, +1733/−109. DropdownMenu, ContextMenu, Layer, MoreMenu, `useMenuPress` and doc-prop suites: 645 tests; header and footer Chromium specs: 15; typecheck, `lint:strict`, `check:knowledge`, Storybook build: clean.

Review round 4 (amended into the last commit): the surface host is owned through a ref, with only a key in state that changes when a host attaches (it moves when the root's header or footer comes or goes); a drilled-in view with regions caps at the root's `menuMaxHeight`. New cases: the view cap (fails on the previous head) and the host move (a guard). Gates below are for this head.

Round 3, then stacked on #7737: the root steps aside for a view by a style rule over its surface host instead of a drill-in record kept in an Effect; a flyout with regions closes from the `onHide` of the flyout holding its row instead of an Effect; the bottom sheet's level regions moved to a follow-up. Each change has a case that fails with it reverted.

- `DropdownMenuSubMenu.test.tsx` "header and footer" suite: 20 cases, plus one in `ContextMenu.test.tsx` (rows alone, with the warning). They cover the dialog's role, modality, name and row wiring; regions outside every menu; the Tab walk and wrap from a field, a row and a deeper flyout; field keys; Escape, an IME Escape and Escapes a region handled; a press from a menu row released on a dialog row (acts) or its field (outside); a menu placed in a region keeping its own press; pointer-leave with focus inside, focus moving within (a header radio's arrow included), then focus leaving; a nested flyout closing with its parent; the phone drill-in, the root stepping aside, a shown view following its regions and its height cap.
- `__tests__/SubMenuHeaderFooter.a11y.chromium.spec.ts`, real Chromium: six cases (laptop structure, keyboard walk, picks, press-drag pick, a header radio after the pointer leaves; phone drill-in with the root stepped aside).
- iOS 26.2 simulator (Mobile Safari), earlier head: phone drill-in as described above; on `main` the level has no field or button.
@vjeux
vjeux force-pushed the header-field-arrows branch from 504b40b to 8a2c3e0 Compare October 21, 2026 21:25

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval is waiting on a maintainer decision: arrow keys that move focus between a header text field and the menu rows join two separately focusable parts, which spec:AST-020 FR15 allows only as a named exception in the owning record, so the DropdownMenu owner needs to approve or decline proposed FR21 and DEC-14 and choose between on by default in a planned minor (main declares 0.7.3, so check:changesets refuses the [breaking] Changeset until then) or an opt-in. If the default-on route is approved, the Compatibility and migration section of DropdownMenu.spec.md also needs to stop saying the released default is preserved and the change is additive documentation, and to name DEC-14 as the migration decision. The implementation, the jsdom suite and the Chromium spec otherwise hold up on this revision.

[Automated review]

| FR16 | `DropdownMenuCheckboxItem` MUST expose one `menuitemcheckbox` row whose `aria-checked` equals its controlled value; enabled activation reports `!value`, stays open by default, and composes consumer click and pointer-move handlers with owned activation and hover focus. Disabled activation calls no consumer activation handler. | Released subcomponent API; `architecture:public-component-api/INV5–INV8`; `DropdownMenuSelectable.test.tsx` | Verified current behavior; consumer handlers are preserved |
| FR17 | Disabled menu rows SHOULD remain keyboard-discoverable while activation stays blocked. Current shared `useListFocus` deliberately skips every `aria-disabled` row, including checkbox items. | WAI-ARIA Menu pattern; current shared navigation source/tests | Objective mismatch; shared mechanism remains undecided in OQ1 |
| FR20 | With `header` or `footer` on a sub-menu (`DropdownMenuSubMenu`), its surface is a modal dialog named by its row (AR7), holding the header, the sub-menu's `role="menu"` (rows only), then the footer. It sits in a host `DropdownMenu` renders beside its menu, never inside a menu; under a root with no such host (`ContextMenu`) the sub-menu shows its rows alone. On a fine pointer the dialog is the flyout; on a compact touch display, the drilled-in view, which replaces the root's menu and regions until popped. A region keeps its own keys and presses. The rows are one Tab stop: Tab and Shift+Tab walk the header's controls, the rows, then the footer's, and wrap; from a deeper flyout, that flyout closes and the walk goes on from the rows. An open lands as for any sub-menu (FR11, FR12), not on a region. Escape in the dialog, outside an IME composition and unless a control there handled it, returns focus to the row and leaves the root open. A pointer leaving the flyout keeps it open until focus leaves, and it closes with the flyout holding its row. Without either prop nothing changes. | Proposed DEC-13; FR15; AR5 | Proposed; verified in jsdom and Chromium, pending owner review |
| FR21 | In the pointer popover, with a single-line text field in `header` (an `input` of type `text`, `search`, `email`, `url`, `tel` or `password`, with no role but `textbox` or `searchbox`), ArrowDown in that field moves focus to the menu's first enabled row, as from a combobox's input to its list, and ArrowUp on that row moves focus back to the field ArrowDown left in this open instead of wrapping to the last row; until a field has, the row wraps as FR12 states. Both keys are handled in full only when focus moves. An arrow with a modifier, a key inside an IME composition, an ArrowDown the field already handled (its own `onKeyDown` prevented the default), and any key in a control whose arrows mean something of their own (a number, a range, a multi-line text, a button, a combobox, a spinbutton, an input with a `list`) keep their native behavior. The bottom sheet, and a drilled-in sub-menu view, hand no arrows between the field and the rows. The menu's other keys (FR12) are unchanged. It is a named exception under `spec:AST-020/FR15` (AR5, DEC-14). | Proposed DEC-14; FR12; FR15; `spec:AST-020/FR15` exception | Proposed; verified in jsdom and Chromium, pending owner review |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This row makes the hand-off on by default, but the record's Compatibility and migration section (lines 53-58) still says "Released default preserved: yes" and "Compatibility class: additive documentation", with a migration decision that names only useMenuPress DECs. If the default-on route is approved, that section should say the released default is not preserved for a header text field's ArrowDown in the popover, classify the change as breaking (minor), and name DEC-14 (prevent the default in the field's own onKeyDown) as the migration decision.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 41a2ee9. The Compatibility and migration section now reads:

  • Released default preserved: no. With proposed FR21, ArrowDown in a single-line text field in header moves focus to the first row, where the released header kept every key of its own.
  • Compatibility class: a breaking interaction change under spec:AST-017 FR1 (proposed FR21).
  • Migration decision: a field that needs ArrowDown prevents its default (proposed DEC-14).

The press-model references stay as they were. Record wording only; the branch is also rebased onto main.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval is waiting on a maintainer decision: arrow keys that move focus between a header text field and the menu rows join two separately focusable parts, which spec:AST-020 FR15 allows only as a named exception in the owning record, so the DropdownMenu owner needs to approve or decline proposed FR21 and DEC-14 and choose between on by default in a planned minor (main declares 0.7.3, so check:changesets refuses the [breaking] Changeset until then) or an opt-in. If the default-on route is approved, the Compatibility and migration section of DropdownMenu.spec.md still needs to stop saying the released default is preserved and the change is additive documentation, and to name DEC-14 as the migration decision. The implementation, the jsdom suite and the Chromium spec otherwise hold up on this revision.

[Automated review]

vjeux added 2 commits October 22, 2026 00:38
… rows

With a single-line text field in header, ArrowDown in the field moves to the
first enabled row, and ArrowUp on the first row returns to the field ArrowDown
left in this open, as between a combobox's input and its list. Modified
arrows, IME composition, a field that prevents ArrowDown's default and
controls with arrows of their own keep their keys; without such a field the
wrap is unchanged. Proposed FR21 and DEC-14 in the DropdownMenu record, with
AR5 naming the exception under AST-020 FR15. pr-a11y runs the header field
arrows Chromium contract.

Rebased onto main after facebook#7530 as one commit; review rounds are folded in
unchanged. Committed with --no-verify: check:changesets rejects [breaking]
while main declares a patch.
…hange to the released default

The Compatibility and migration section still said the released default was preserved and the change was additive documentation, while proposed FR21 hands ArrowDown from a header text field to the rows, where the released header kept every key of its own. It now says the released default is not preserved, names the change as breaking under spec:AST-017 FR1 and gives the migration from proposed DEC-14: a field that needs ArrowDown prevents its default. Record wording only. Committed with --no-verify: check:changesets rejects [breaking] while main declares a patch; check:knowledge and prettier pass.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approval is waiting on a maintainer decision: arrow keys that move focus between a header text field and the menu rows join two separately focusable parts, which spec:AST-020 FR15 allows only as a named exception in the owning record, so the DropdownMenu owner needs to approve or decline proposed FR21 and DEC-14 as the governing spec for it, and choose between on by default in a planned minor (main declares 0.7.3, so check:changesets refuses the [breaking] Changeset until then) or an opt-in. The Compatibility and migration fix from the last round is in, and the implementation, the jsdom suite and the Chromium spec hold up on this revision, so nothing else is needed from you until that decision lands. If the owner picks the opt-in, the hand-off will need that new surface and a compatible Changeset.

[Automated review]

This branch was successfully deployed

1 active deployment
Preview — 41a2ee95 Deployed Oct 22, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant