Skip to content

fix(Layer, Selector): the overlay slides above the software keyboard and keeps its top - #10169

Merged
cixzhang merged 9 commits into
meta:mainfrom
vjeux:uikit/layer-keyboard-inset
Nov 6, 2026
Merged

cixzhang merged 9 commits into
meta:mainfrom
vjeux:uikit/layer-keyboard-inset

Conversation

@vjeux

@vjeux vjeux commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Review only this PR's change: 010db3f...vjeux:astryx:48010db7cf54877e44d3f09656ca9fb83e5cd3eb (against main 010db3f). Its own commits: vjeux@4c9639d vjeux@6181c73 vjeux@46acf05 and vjeux@f21f5b9; the rest are merges from main.

User impact

On a phone, a Selector opened over its trigger while a software keyboard is up can run under the keyboard. When the list's viewport clamp places it below the keyboard's line, the layer runtime's keyboard cap shrinks it to a sliver, or leaves it under the keyboard, and its options cannot be reached. With this change the list slides up and ends 10 px above the keyboard with every option in view. Once open, it keeps its top until it closes: when the keyboard goes, it stays where a finger is already reaching. Without a keyboard nothing changes.

Problem and solution fit

  1. Why does the list run under the keyboard? The overlay clamps the list to the layout viewport's bottom, and the keyboard covers that bottom.
  2. Why can the runtime's cap not fix it alone? The cap keeps a layer's block-start edge and shrinks its block size. The overlay puts that edge over the trigger, which can sit just above the keyboard's line or under it, so little or nothing is left to show.
  3. Why does that matter? The selected option and its neighbors are the ones a person picks from, and a sliver or a hidden list blocks the pick.

The runtime now publishes the keyboard's block-end inset on each open anchor-mode layer, beside its cap. The overlay reads it as a CSS term of its block-start margin, so the list moves in the commit that publishes the inset, before the cap reads its box. The cap then shrinks only a list taller than the room above the keyboard.

In Safari on iOS, a tap on the trigger moves focus off the text field, and the keyboard goes, but Safari keeps reporting it for up to about a second. A person is already reaching for an option then, so a list that moved back down would put a different option under the finger. The inset therefore keeps its largest value until the layer closes: the list keeps its top, and a list the cap held grows downward in place. A keyboard that rises while the list is open still moves it up above it, and a shorter keyboard then leaves it there.

Expected behavior and authority

  • component:Selector FR2: without explicit placement, a non-search popover aligns the selected row over the trigger and clamps it to the viewport. This change adds "above any software keyboard" and "a keyboard that goes down while it is open does not move it".
  • spec:AST-059 FR9: an anchor-mode layer ends 10 px above the software keyboard. The inset is recorded there, beside the cap, as private runtime state that keeps its largest value until the layer closes.
  • architecture:layer-runtime INV11 gains: "A layer that reads the keyboard inset and was placed while a keyboard is reported keeps its top until it closes: when the cap lifts it grows downward in place; when the keyboard rises it moves up above it and then holds."
  • Specs decisions, Nov 5 2026: the keyboard inset is its own change and stays private (an internal name the API report does not list, written only by the layer runtime); once open, the list stays put until it closes; only layers that read the inset hold their place, and every other anchored layer keeps spec:AST-059 FR10's timing.

Smallest restoration

  • Layer runtime (useLayerKeyboardClearance.ts, useLayer.tsx): a third private custom property beside the cap and the overflow, --_layer-keyboard-inset-block-end. Once a keyboard is up it holds the keyboard's height plus the 10 px clearance, and it keeps its largest value until the layer closes; before that it is initial, so a nested layer does not inherit it. It is committed with the cap lifted, before the cap measures. The cap itself is unchanged: it still lifts at once as the keyboard goes down.
  • Selector (hooks.ts, Selector.tsx): an internal useSelectedItemOverlayMargin returns the overlay's margin as min(<measured shift>, max(<viewport top>, calc(<room> − var(<inset>, <room>)))). Without an inset the second term is 0, so the measured shift stands. The margin reaches the layer through a Selector-private custom property that margin-block-start reads. The public useSelectedItemOffset is unchanged.
  • A story, "Overlay beside keyboard", for a check on a phone.
  • No public API: pnpm api:report on this head writes the same report as on main.

Evidence

  • Reproduction before the change: SelectorKeyboardInset.a11y.chromium.spec.ts on main's build, with a stand-in software keyboard covering the lower 300 px of a 390 × 844 viewport (its line at 534 px), fails 13 of 13 (dc7fc55 is its first form alone on main, not for landing). Each case first checks that the list and its options are on screen.

    • Trigger at 496–516 px: the list is capped at 461–534 px with 2 of its 4 options above the keyboard.
    • Trigger at 566–586 px: an 8 px list.
    • Trigger at 606–626 px: the list at 571–707 px, 173 px under the keyboard's line.
  • Result after the change: the same spec passes 13 of 13, twice, with every option above the keyboard.

  • The list keeps its top: without the hold (the earlier head, 4c9639d), 7 of the 13 cases fail and this head passes them.

    • When the keyboard's report ends, the list moved back down in the next frame, from 398 px to 461, 531 or 571 px.
    • Against a shorter keyboard, a list that slid above a late keyboard moved down, from 398 px to 461 or 498 px.
    • A 300 px list held above a keyboard that leaves 210 px (the Long List story at a 600 px viewport) moved down 33 px when the report ended, its third visible option with it. With the hold, its top and that option stay, and the list grows from 210 to 300 px.
  • iOS 26.2 simulator, Safari, the "Overlay beside keyboard" story, three takes per build. A tap in the Name field raises the keyboard; a tap on the Selector's trigger moves focus to it, and the keyboard goes. Safari keeps reporting the keyboard for 0.2–0.6 s after that tap.

    • Main: in that window the list opens over its trigger, capped to 3 of its 6 options in two takes, and grows to 6 when the report ends.
    • This change: the list opens with all 6 options above the keyboard, and stays there: its top did not move in any reading, taken every 100 ms for 2.6 s, in any take.

    Top: while Safari still reports the keyboard after the tap. Bottom: after the report ends. Left: main. Right: this change.

    The Selector's list on iOS: main and this change, while the keyboard is reported up and after

  • Representative unchanged path: an anchored layer that does not read the inset still loses its cap at once as the keyboard goes down (a unit case, where that moves it back over its trigger); Popover's keyboard proofs and the capped lists' keyboard proofs pass in Chromium, 14 of 14, and Popover's in WebKit, 6 passed and 1 skipped.

  • Regression tests: runtime unit cases check that the inset grows with a taller keyboard, holds against a shorter one or none, and clears when the layer closes, and that a layer that places itself by it keeps its top. Two of them fail when the hold is removed. A runtime unit case checks that a layer that places itself by the inset is not capped; it fails when the inset is published after the box is read. Selector's unit cases check the margin's expression with and without the keyboard term.

Scope

  • One defect is restored.
  • Separable contradictory or unsettled tagalongs were removed or split.
  • No new public API, visual representation, default, or interaction model is hidden under the bug-fix label.
  • Public text and artifacts contain no internal Meta context.

Testing

  • pnpm test:ui --maxWorkers=16: 851 files, 21,300 tests (before main was merged in).
  • After main was merged in (48010db): Selector, Layer and theme registry units, 34 files, 972 tests; core typecheck; pnpm check:knowledge; SelectorKeyboardInset.a11y.chromium.spec.ts, 13 of 13, twice.
  • pnpm -F @astryxdesign/core typecheck; CI=true pnpm exec eslint on the changed files: 0 problems; pnpm -F @astryxdesign/storybook typecheck.
  • pnpm check:knowledge; pnpm api:report (no change against main's own report).
  • Chromium: SelectorKeyboardInset.a11y.chromium.spec.ts; Selector's accessibility specs; PopoverKeyboard.interaction.browser.spec.ts; keyboardCappedLists.interaction.browser.spec.ts. WebKit (container): PopoverKeyboard.interaction.browser.spec.ts.
  • pnpm storybook:build (the story file changed).

Writing rubric results

Run over the sentences this change adds to spec:AST-059 FR9 and its FR9 verification row, component:Selector FR2 and its verification row, and architecture:layer-runtime INV11 and its "INV11, INV12" verification row:

  • R1 narration: none; the added text states what the runtime and the overlay do, in the present tense.
  • R2 research: none.
  • R3 evidence: the added text cites nothing except FR9, which the Selector row names as the requirement it qualifies; the verification rows name the tests.
  • R4 rejected alternatives: none added.
  • R5 change references: none added.
  • R6 open questions: none added to any of the three records.

vjeux added 2 commits November 5, 2026 10:12
INV11 names the software keyboard's cap among the viewport caps, and
the overflow each layer carries beside it. INV12 names the cap as the
second change permitted after paint: once per keyboard movement, and
after a press's click. It also names where the cap reads the layer's
box. The change coupling, owning code and verification sections name
the cap's checks, its modules and its tests.
The layer runtime now writes the software keyboard's block-end inset
on each open anchor-mode layer, beside its keyboard cap: the keyboard's
height and the 10 px clearance. It is a private custom property that
only the runtime writes. It goes out in the commit that lifts the cap,
before the cap reads the layer's box.

Selector's selected-item overlay reads it as a CSS term of its
block-start margin. With a keyboard up, the list ends above the
keyboard instead of shrinking to a sliver or opening under it. Without
one, the measured shift stands.
@vercel

vercel Bot commented Nov 5, 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 Nov 6, 2026 9:17pm UTC

Request Review

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

astracat-bot Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

AI review status for this pull request.

Review status Updated
🟢 Reviewed (for maintainers only) Nov 6, 2026, 9:29 PM UTC

@github-actions github-actions Bot added the needs:design-review Affects visuals — Design should review label Nov 5, 2026
@github-actions github-actions Bot added the needs:spec-owner-review Current knowledge records await owner approval label Nov 5, 2026
@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

🔎 Preview · 990d94c

Storybook · Sandbox · built from this PR's head

Modified components

Component Size LoC Visual · A11y · RTL
Selector 94.2 kB (+290 B) · 17.0 kB CSS (+18 B) — ✗ · ✓ · ✓
LayerProvider 4.1 kB (0) · 20 B CSS (0) — ✓ · ✓ · ✗
SelectorOption 19.5 kB (0) · 5.8 kB CSS (0) — ✗ · ✓ · ✓
113 more components
Component Size LoC Visual · A11y · RTL
CommandPalette 🔴 67.1 kB (+7.4 kB) · 12.4 kB CSS (+20 B) — — · — · —
PowerSearch 275.4 kB (+318 B) · 23.2 kB CSS (+13 B) — — · — · —
richtext/RichTextEditorToolbar 245.4 kB (+307 B) · 454 B CSS (0) — — · — · —
Pagination 104.3 kB (+274 B) · 17.3 kB CSS (+18 B) — — · — · —
AvatarGroupOverflow 44.8 kB (+184 B) · 5.5 kB CSS (+18 B) — — · — · —
DateTimeInput 199.5 kB (+172 B) · 18.2 kB CSS (+22 B) — — · — · —
SegmentedControl 89.8 kB (+175 B) · 6.8 kB CSS (+19 B) — — · — · —
InfoTip 43.6 kB (+166 B) · 5.3 kB CSS (+20 B) — — · — · —
StatusDot 27.9 kB (+167 B) · 5.3 kB CSS (+19 B) — — · — · —
TableCell 92.6 kB (+166 B) · 17.1 kB CSS (+19 B) — — · — · —
DropdownMenuSubMenu 65.0 kB (+165 B) · 9.4 kB CSS (+19 B) — — · — · —
Typeahead 74.8 kB (+162 B) · 12.2 kB CSS (+21 B) — — · — · —
TableHeaderCell 92.2 kB (+162 B) · 16.8 kB CSS (+19 B) — — · — · —
BreadcrumbItem 76.3 kB (+161 B) · 11.6 kB CSS (+18 B) — — · — · —
CheckboxListItem 66.2 kB (+160 B) · 11.0 kB CSS (+19 B) — — · — · —
Carousel 60.9 kB (+160 B) · 10.4 kB CSS (+18 B) — — · — · —
FileInput 64.6 kB (+157 B) · 10.7 kB CSS (+18 B) — — · — · —
DateInput 177.1 kB (+155 B) · 16.5 kB CSS (+19 B) — — · — · —
ListItem 65.2 kB (+154 B) · 11.0 kB CSS (+19 B) — — · — · —
Switch 96.7 kB (+153 B) · 9.9 kB CSS (+18 B) — — · — · —
Slider 102.1 kB (+148 B) · 8.7 kB CSS (+22 B) — — · — · —
TopNav 63.9 kB (+154 B) · 10.3 kB CSS (+16 B) — — · — · —
AvatarGroup 42.5 kB (+150 B) · 5.6 kB CSS (+19 B) — — · — · —
ChatComposer 68.7 kB (+151 B) · 11.3 kB CSS (+18 B) — — · — · —
lab/CommentPin 53.0 kB (+168 B) · 1.2 kB CSS (0) — — · — · —
Tooltip 26.2 kB (+147 B) · 4.3 kB CSS (+19 B) — — · — · —
ChatComposerInput 66.8 kB (+145 B) · 10.7 kB CSS (+20 B) — — · — · —
ChatComposerTokenElement 66.8 kB (+145 B) · 10.7 kB CSS (+20 B) — — · — · —
ContextMenu 91.4 kB (+146 B) · 16.7 kB CSS (+19 B) — — · — · —
DropdownMenu 87.6 kB (+148 B) · 16.8 kB CSS (+17 B) — — · — · —
TabMenu 63.5 kB (+147 B) · 10.5 kB CSS (+17 B) — — · — · —
Table 100.8 kB (+144 B) · 17.3 kB CSS (+19 B) — — · — · —
charts/Chart 180.6 kB (+161 B) · 494 B CSS (0) — — · — · —
CheckboxList 54.6 kB (+141 B) · 8.0 kB CSS (+20 B) — — · — · —
SideNavHeading 67.2 kB (+140 B) · 10.7 kB CSS (+21 B) — — · — · —
Avatar 39.8 kB (+140 B) · 5.5 kB CSS (+20 B) — — · — · —
ComplexSelector 66.2 kB (+141 B) · 11.5 kB CSS (+19 B) — — · — · —
TabList 40.5 kB (+140 B) · 6.4 kB CSS (+20 B) — — · — · —
TimeInput 153.9 kB (+139 B) · 15.6 kB CSS (+21 B) — — · — · —
HoverCard 24.7 kB (+139 B) · 4.3 kB CSS (+20 B) — — · — · —
MoreMenu 87.9 kB (+141 B) · 16.8 kB CSS (+17 B) — — · — · —
MobileNav 62.2 kB (+141 B) · 10.1 kB CSS (+16 B) — — · — · —
TopNavMenu 66.3 kB (+138 B) · 10.6 kB CSS (+19 B) — — · — · —
AlertDialog 96.3 kB (+138 B) · 13.8 kB CSS (+18 B) — — · — · —
SideNav 81.8 kB (+140 B) · 10.8 kB CSS (+16 B) — — · — · —
TextArea 58.2 kB (+135 B) · 9.2 kB CSS (+21 B) — — · — · —
FieldLabel 47.4 kB (+134 B) · 5.6 kB CSS (+21 B) — — · — · —
TopNavHeading 66.6 kB (+139 B) · 10.5 kB CSS (+16 B) — — · — · —
lab/CommentComposer 139.3 kB (+155 B) · 1.9 kB CSS (0) — — · — · —
charts/ChartTooltip 158.0 kB (+154 B) · 423 B CSS (0) — — · — · —
BaseTypeahead 62.4 kB (+137 B) · 10.4 kB CSS (+17 B) — — · — · —
AppShell 82.0 kB (+138 B) · 12.9 kB CSS (+14 B) — — · — · —
Calendar 63.1 kB (+137 B) · 10.0 kB CSS (+15 B) — — · — · —
Lightbox 103.4 kB (+136 B) · 9.9 kB CSS (+16 B) — — · — · —
SideNavCollapseButton 52.9 kB (+136 B) · 9.5 kB CSS (+16 B) — — · — · —
Tokenizer 86.2 kB (+131 B) · 18.2 kB CSS (+21 B) — — · — · —
DateRangeInput 87.0 kB (+131 B) · 12.2 kB CSS (+20 B) — — · — · —
RadioList 52.1 kB (+131 B) · 7.2 kB CSS (+20 B) — — · — · —
RadioListItem 63.0 kB (+130 B) · 9.8 kB CSS (+20 B) — — · — · —
ToggleButton 53.0 kB (+134 B) · 9.5 kB CSS (+16 B) — — · — · —
TopNavMegaMenu 61.4 kB (+133 B) · 11.3 kB CSS (+16 B) — — · — · —
ChatSendButton 52.5 kB (+131 B) · 9.4 kB CSS (+17 B) — — · — · —
InputGroup 52.4 kB (+128 B) · 7.8 kB CSS (+20 B) — — · — · —
Markdown 163.2 kB (+131 B) · 19.6 kB CSS (+17 B) — — · — · —
lab/TransferList 91.4 kB (+148 B) · 1.7 kB CSS (0) — — · — · —
Button 52.1 kB (+131 B) · 9.4 kB CSS (+16 B) — — · — · —
IconButton 52.1 kB (+131 B) · 9.4 kB CSS (+16 B) — — · — · —
Thumbnail 56.4 kB (+132 B) · 11.0 kB CSS (+15 B) — — · — · —
lab/Schedule 100.1 kB (+147 B) · 3.9 kB CSS (0) — — · — · —
Banner 54.2 kB (+129 B) · 9.9 kB CSS (+17 B) — — · — · —
ChatDictationButton 52.7 kB (+130 B) · 9.5 kB CSS (+16 B) — — · — · —
TableSelectionToolbar 61.6 kB (+130 B) · 12.5 kB CSS (+16 B) — — · — · —
ChatLayoutScrollButton 52.6 kB (+128 B) · 9.6 kB CSS (+17 B) — — · — · —
CodeBlock 66.8 kB (+130 B) · 10.7 kB CSS (+15 B) — — · — · —
DrawerHeader 55.1 kB (+129 B) · 12.3 kB CSS (+16 B) — — · — · —
Field 50.8 kB (+124 B) · 7.2 kB CSS (+21 B) — — · — · —
Popover 80.0 kB (+127 B) · 13.5 kB CSS (+17 B) — — · — · —
ChatLayout 55.4 kB (+126 B) · 9.9 kB CSS (+17 B) — — · — · —
MobileNavToggle 52.4 kB (+127 B) · 9.4 kB CSS (+16 B) — — · — · —
SideNavItem 62.1 kB (+127 B) · 10.5 kB CSS (+16 B) — — · — · —
Stepper 53.8 kB (+128 B) · 9.6 kB CSS (+15 B) — — · — · —
Toolbar 39.8 kB (+124 B) · 7.9 kB CSS (+19 B) — — · — · —
DialogHeader 54.9 kB (+124 B) · 10.9 kB CSS (+17 B) — — · — · —
Toast 89.7 kB (+125 B) · 9.7 kB CSS (+16 B) — — · — · —
lab/TourStep 86.2 kB (+141 B) · 590 B CSS (0) — — · — · —
CheckboxInput 60.1 kB (+119 B) · 9.1 kB CSS (+21 B) — — · — · —
Link 49.0 kB (+120 B) · 7.0 kB CSS (+20 B) — — · — · —
NumberInput 67.2 kB (+121 B) · 11.2 kB CSS (+19 B) — — · — · —
MultiSelector 89.5 kB (+116 B) · 16.4 kB CSS (+22 B) — — · — · —
lab/DiffViewer 78.5 kB (+137 B) · 2.1 kB CSS (0) — — · — · —
TextInput 63.2 kB (+116 B) · 10.9 kB CSS (+20 B) — — · — · —
lab/ChatEmojiPicker 97.9 kB (+136 B) · 773 B CSS (0) — — · — · —
lab/CommentThread 302.8 kB (+136 B) · 2.4 kB CSS (0) — — · — · —
lab/Comments 307.9 kB (+132 B) · 2.5 kB CSS (0) — — · — · —
lab/TransferListSelector 98.4 kB (+132 B) · 1.9 kB CSS (0) — — · — · —
lab/EmojiPicker 81.7 kB (+130 B) · 751 B CSS (0) — — · — · —
richtext/RichTextEditor 291.3 kB (+130 B) · 2.6 kB CSS (0) — — · — · —
lab/ChatReactionBar 99.1 kB (+129 B) · 1.1 kB CSS (0) — — · — · —
richtext/RichTextView 271.5 kB (+127 B) · 2.3 kB CSS (0) — — · — · —
lab/ListInput 96.6 kB (+126 B) · 1.6 kB CSS (0) — — · — · —
lab/SelectableCardGroup 60.0 kB (+122 B) · 162 B CSS (0) — — · — · —
Heading 8.2 kB (+1 B) · 5.4 kB CSS (+20 B) — — · — · —
ChatMessageList 23.9 kB (0) · 7.0 kB CSS (+20 B) — — · — · —
Spinner 20.5 kB (0) · 6.1 kB CSS (+20 B) — — · — · —
Text 7.6 kB (0) · 5.4 kB CSS (+20 B) — — · — · —
ChatToolCalls 27.8 kB (−1 B) · 8.3 kB CSS (+20 B) — — · — · —
CommandPaletteInput 27.9 kB (0) · 7.5 kB CSS (+19 B) — — · — · —
Timer 9.7 kB (0) · 5.9 kB CSS (+19 B) — — · — · —
ProgressBar 11.5 kB (−1 B) · 6.2 kB CSS (+19 B) — — · — · —
Timestamp 23.2 kB (−2 B) · 9.7 kB CSS (+19 B) — — · — · —
charts/ChartLegend 35.8 kB (−3 B) · 224 B CSS (0) — — · — · —
layer — — — · ✓ · —
Layer — — ✓ · ✓ · —
Visual changes: 8 snapshots in 1 component

A change is a question for the reviewer, not a failure.

Component · story Before After Diff
Selector · Indicator Space Bottom Sheet Narrow End RTL (neutral, light) before frame after frame diff frame
Selector · Indicator Space Bottom Sheet Wide Start (neutral, light) before frame after frame diff frame
Selector · Indicator Space Popover Wide End RTL (neutral, light) before frame after frame diff frame
Selector · Indicator Space Popover Wide End RTL (neutral, dark) before frame after frame diff frame
Selector · Indicator Space Bottom Sheet Narrow End RTL (neutral, dark) before frame after frame diff frame
Selector · Indicator Space Bottom Sheet Wide Start (neutral, dark) before frame after frame diff frame
Selector · Indicator Space Popover Narrow Start (neutral, dark) before frame after frame diff frame
Selector · Indicator Space Popover Narrow Start (neutral, light) before frame after frame diff frame

Package size: @astryxdesign/core 6.82 MB packed (+3.2 kB); no new dependencies.

API changes: none in this pull request

Committed API report behind this build: cli 19 rows, core 24 rows; run pnpm api:report.

Touched components checked; add ci:run-visual or ci:run-rtl to run the full suites.


Generated by PR Enrichment workflow | View full report

vjeux added 2 commits November 5, 2026 14:43
The layer-runtime record's keyboard cap text comes with meta#10143.
The runtime now keeps the keyboard inset at its largest value until the
layer closes. Selector's overlay reads it, so it keeps its top when the
keyboard's report ends: a list the cap held grows downward in place. A
keyboard that rises while it is open still moves it up above it, and a
shorter keyboard then leaves it there. Every other anchored layer keeps
its timing: its cap still lifts at once as the keyboard goes down.

The layer-runtime record states this beside the keyboard cap.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approval waits on a spec decision. This pull request adds new requirement text to two current records, and an engineering owner needs to approve that text first.

What must be settled:

  • spec:AST-059 FR9: the layer runtime writes a private keyboard block-end inset on each open anchored layer. A layer that places itself, such as Selector's overlay, moves its top edge to end 10 px above the keyboard, where FR9 today keeps that edge and only caps the layer.
  • component:Selector FR2: the viewport clamp now includes "above any software keyboard".
  • architecture:react-component-runtime INV11 lets the keyboard height reach styles only through a functional style on the consumer's own element. The decision should confirm that the private inset property fits that rule.

An engineering owner records the decision by commenting /approve-spec <full head SHA> on this pull request; the author may do so if they are an engineering owner. Beyond that decision the review found no defect. With a stand-in keyboard, the list ends above the keyboard with every option in view, and without a keyboard the overlay renders exactly as before. CI has not run on this head yet.

[Automated review]

Comment thread packages/core/src/Selector/Selector.tsx Resolved
Comment thread packages/core/src/Selector/hooks.ts Resolved
@vjeux vjeux changed the title fix(Layer, Selector): the overlay slides above the software keyboard fix(Layer, Selector): the overlay slides above the software keyboard and keeps its top Nov 5, 2026
vjeux added 2 commits November 5, 2026 14:56
The overlay margin property's comment keeps only its constraint, and
the margin field drops a note that restated its name and type.
The INV11 line about layers that read the keyboard inset now says a
layer placed while a keyboard is reported, which is what the runtime
does: it cannot tell a lingering report from a keyboard that was up.
@cixzhang

cixzhang commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

/approve-spec 48445f6

@github-actions github-actions Bot removed the needs:spec-owner-review Current knowledge records await owner approval label Nov 5, 2026
@vjeux

vjeux commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

On the architecture:react-component-runtime INV11 point: the inset is written by the same keyboardCap functional style as the keyboard cap, on the layer's own element, and it is initial until a keyboard is reported, so a nested layer does not inherit it. Selector reads it through var() in a style on that same element. No custom property for it is set on the document root or on a shared ancestor.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved pending CI: CI has not run on this head yet; as a draft from a fork, it starts once the pull request is marked ready for review and a maintainer adds the ci:run label.

With a software keyboard up, the Selector's list now ends above the keyboard with every option in view and keeps its top when the keyboard goes, while without a keyboard it opens exactly where it did. The record text in spec:AST-059 FR9, component:Selector FR2 and the layer-runtime INV11 line has an engineering owner's approval for this head, no public API changes, and both earlier comment notes are addressed.

[Automated review]

@vjeux
vjeux marked this pull request as ready for review November 5, 2026 23:41
@vjeux
vjeux requested a review from josephfarina as a code owner November 5, 2026 23:41
@cixzhang cixzhang added the ci:run A maintainer lets this outside contributor's pull request run CI (AST-030 FR17) label Nov 5, 2026
@cixzhang
cixzhang marked this pull request as draft November 5, 2026 23:44
@cixzhang
cixzhang marked this pull request as ready for review November 5, 2026 23:44
@cixzhang cixzhang added the ci:run-a11y Run the accessibility suite on this PR; write access, next push (AST-030 FR12) label Nov 6, 2026
@cixzhang
cixzhang marked this pull request as draft November 6, 2026 03:10
@cixzhang
cixzhang marked this pull request as ready for review November 6, 2026 03:10
Main brought the exit copy's INV13 row (meta#8186), the searchable
Selector trigger's name (meta#10170) and AST-059's scroll placement
(meta#10255, meta#10257, meta#10289). Their verification tables re-padded, so each
conflicted as a whole table. Resolved row by row: the layer-runtime
table keeps this branch's INV11, INV12 row, then main's INV13 row.
AST-059's table keeps main's FR4 tooltip row and new scroll row, with
this branch's FR9 row. Selector's table keeps main's AR1, AV2 row and
this branch's FR2 row.
@github-actions github-actions Bot added the needs:spec-owner-review Current knowledge records await owner approval label Nov 6, 2026
@cixzhang

cixzhang commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

/approve-spec 48010db

@github-actions github-actions Bot removed the needs:spec-owner-review Current knowledge records await owner approval label Nov 6, 2026

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved pending CI: the required test check is red at this head and needs a rerun before this can merge.

  • The two failing jobs do not come from this change: one Popover touch-motion case (PopoverTouchMotion.interaction.browser.spec.ts:590) passes when run again against this head's Storybook build, and the component accessibility suite stopped at its 8-minute budget with every test that ran passing, this pull request's own keyboard spec included.

With a software keyboard up, the Selector's list now ends above the keyboard with every option in view and keeps its top when the keyboard goes; without a keyboard it opens exactly where it did. The record text in spec:AST-059 FR9, component:Selector FR2 and the layer-runtime INV11 line has an engineering owner's approval for this head, and no public API changes.

[Automated review]

@github-actions github-actions Bot added the needs:spec-owner-review Current knowledge records await owner approval label Nov 6, 2026
@cixzhang

cixzhang commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

/approve-spec 990d94c

@github-actions github-actions Bot removed the needs:spec-owner-review Current knowledge records await owner approval label Nov 6, 2026

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved: required CI passed on this head.

The default Selector overlay now slides above a software keyboard and keeps its top until it closes, and the record text it adds to spec:AST-059 FR9, component:Selector FR2 and architecture:layer-runtime INV11 carries an engineering owner's approval for this head. The merge from main leaves this pull request's own patch unchanged, and the stand-in keyboard checks in Chromium give the same geometry as before. There are no blocking findings.

[Automated review]

@cixzhang
cixzhang merged commit a5b485e into meta:main Nov 6, 2026
73 checks passed
@vjeux
vjeux deleted the uikit/layer-keyboard-inset branch November 6, 2026 21:41

This branch was successfully deployed

1 active deployment
Preview — 990d94c6 Deployed Nov 6, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:run A maintainer lets this outside contributor's pull request run CI (AST-030 FR17) ci:run-a11y Run the accessibility suite on this PR; write access, next push (AST-030 FR12) CLA Signed This label is managed by the Meta Open Source bot. needs:design-review Affects visuals — Design should review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants