Menu ignores the keyboard when it mounts while the keyboard is already open
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- ios, react-native, typescript
Research direction
Start in src/components/Menu/Menu.tsx, reading show() and the mount effect that registers keyboard listeners. Reproduce the conditional Menu with an already-focused TextInput as described, then verify the menu measures the available height and its overflow scrolling remains usable when the keyboard is open. Check how the behavior applies on Android before considering the fix complete.
Written by the indexing model from the issue text.
Description
Summary
Menu accounts for the on-screen keyboard, but it learns the keyboard height only from a keyboardDidShow event that arrives after it mounts. iOS does not replay that event for a keyboard that is already open, so a Menu that mounts while the keyboard is already up keeps a height of 0, measures against the full window, and lays its items out underneath the keyboard — where they cannot be tapped, and where its own overflow scrolling never engages, because as far as it knows the items fit.
Current behaviour
src/components/Menu/Menu.tsx in 5.14.5:
- L215 —
const keyboardHeightRef = React.useRef(0); - L221-228 —
keyboardDidShow/keyboardDidHideset and clear that ref. - L413-420 — both listeners are attached inside a mount effect.
- L343 —
show()uses the ref:height: windowLayoutResult.height - keyboardHeightRef.current
When the keyboard is already visible at mount, no keyboardDidShow arrives, the ref stays 0, and L343 subtracts nothing.
Why this shows up in practice
Any menu that belongs to a row created while the user is typing. In our app a text field searches for people, and each person added brings a row with its own Menu. The field keeps focus (keyboardShouldPersistTaps="handled"), so every one of those menus mounts with the keyboard already open.
Two menus on one screen, same bundle and same keyboard state, made the cause unambiguous:
| Menu | Mounts | Keyboard height it believes | Result |
|---|---|---|---|
| Rendered with the screen | Before any keyboard | correct | 9 items, correctly placed clear of the keyboard |
| Rendered into a row added while typing | Keyboard already open | 0 |
Ran to y=737 with the keyboard top at y=509; the last 6 items were untappable |
Steps to reproduce
- Render a
TextInputinside aScrollViewwithkeyboardShouldPersistTaps="handled". - Render a
Menuconditionally, so that it mounts only after the input has text — for example{value.length > 0 && <Menu ... />}. - Give the menu enough items to reach past the keyboard (about 8 on a 390×844 screen).
- Focus the input, type a character, then tap the anchor without dismissing the keyboard.
The menu extends under the keyboard. Mount the same menu unconditionally and it positions correctly.
Expected behaviour
The menu measures against the space the keyboard leaves, whenever it mounted.
Suggested fix
Read the current keyboard metrics at open time instead of relying only on events. In show():
setWindowLayout({
- height: windowLayoutResult.height - keyboardHeightRef.current,
+ height:
+ windowLayoutResult.height -
+ (Keyboard.metrics()?.height ?? keyboardHeightRef.current),
width: windowLayoutResult.width,
});
Keyboard.metrics() returns undefined when the keyboard is not shown, so the existing ref stays as the fallback.
I have not tested this patch. I worked around the problem in application code instead, and I have not checked how Keyboard.metrics() behaves on Android.
Workaround
Call Keyboard.dismiss() before opening the menu. That makes the component's assumption true. It costs nothing in our case, because choosing from a menu is not typing.
Environment
- react-native-paper 5.14.5
- react-native 0.81.5
- Expo SDK 54
- iOS 26.2, iPhone 16e simulator
- Dominant language
- TypeScript
- Stars
- 14.5k
- Forks
- 2.2k
- Avg merge
- 5d 23h
- Merged PRs (30d)
- 11
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from callstack/react-native-paper
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
callstack/react-native-paper#5093 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
callstack/react-native-paper#5003 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
callstack/react-native-paper#4951 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
callstack/react-native-paper#4881 ·
-
feature request
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
callstack/react-native-paper#4863 · 1 comment ·
All issues in callstack/react-native-paper
Similar issues
-
S: triage
Difficulty 1/5 Under an hour Newbie friendliness 85/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
fix(errors): EHOSTUNREACH from a happy-eyeballs connect is reported as a resolver error (STAMP-80) Open
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
snapshot-labs/stamp#666 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
GauravKarakoti/SecureFlow#1070 · 1 comment ·
-
feature:Languages/Translations good first issue ready Web
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
digitalfabrik/integreat-app#4394 ·