Skip to content

Add shouldDismissKeyboardOnTap property to ScrollView - #57875

Open
m-bert wants to merge 2 commits into
react:mainfrom
m-bert:@mbert/scrollview-should-dismiss-keyboard-on-tap
Open

Add shouldDismissKeyboardOnTap property to ScrollView#57875
m-bert wants to merge 2 commits into
react:mainfrom
m-bert:@mbert/scrollview-should-dismiss-keyboard-on-tap

Conversation

@m-bert

@m-bert m-bert commented Aug 10, 2026

Copy link
Copy Markdown

Summary:

While fixing software-mansion/react-native-gesture-handler#4328 we found that ScrollView with keyboardShouldPersistTaps="handled" decides whether a tap was "handled" purely through the responder system: if no child claims the start-should-set negotiation, ScrollView claims the responder and dismisses the keyboard on release. Components that handle touches outside of the responder system (native gesture recognizers, Gesture Handler buttons, etc.) never claim the responder, so taps on them always dismiss the keyboard. We got out of it with disableScrollViewPanResponder + reimplementing the 'handled' dismissal ourselves, but that means copying ScrollView internals.

This PR adds an opt-in shouldDismissKeyboardOnTap prop, consulted as one extra condition in the existing "handled" claim. Returning false marks the tap as already handled and keeps the keyboard up. When the prop is not set, behavior is unchanged. The prop has no effect in "never" and "always" modes.

Changelog:

[GENERAL] [ADDED] - Add shouldDismissKeyboardOnTap prop to ScrollView

Test Plan:

  • Added ScrollView-shouldDismissKeyboardOnTap-test.js covering the default claim, the veto, and the cases where the callback must not be consulted (keyboard down, tap on the focused input, "never"/"always" modes). Ran with yarn jest packages/react-native/Libraries/Components/ScrollView.
  • yarn flow check, yarn lint, yarn build-types (ReactNativeApi.d.ts snapshot updated; addition only, no changes to existing API shapes).
  • Verified end to end in an app: patched this change into react-native and rewired react-native-gesture-handler to pass shouldDismissKeyboardOnTap={() => !handledByGesture}. Taps on Gesture Handler buttons and gesture detectors keep the keyboard up, taps on empty space dismiss it, and stickyHeaderIndices keeps working.

Copilot AI lite review requested due to automatic review settings August 10, 2026 11:35
@meta-cla

meta-cla Bot commented Aug 10, 2026

Copy link
Copy Markdown

Hi @m-bert!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks!

@github-actions

Copy link
Copy Markdown

Warning

JavaScript API change detected

This PR commits an update to ReactNativeApi.d.ts, indicating a change to React Native's public JavaScript API.

  • Please include a clear changelog message.
  • This change will be subject to additional review.

This change was flagged as: POTENTIALLY_BREAKING

Copilot AI 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.

Pull request overview

This PR introduces an opt-in shouldDismissKeyboardOnTap callback on ScrollView to refine keyboardShouldPersistTaps="handled" behavior, allowing non-responder-based touch handlers (e.g. native recognizers / gesture-handler buttons) to prevent keyboard dismissal for specific taps without reimplementing ScrollView internals.

Changes:

  • Add shouldDismissKeyboardOnTap prop and consult it as an additional condition for the "handled" responder-claim path.
  • Update TypeScript/public API typings to include the new prop.
  • Add Jest coverage validating default behavior, veto behavior, and non-consulted cases.

Reviewed changes

Copilot reviewed 2 out of 4 changed files in this pull request and generated 1 comment.

File Description
packages/react-native/Libraries/Components/ScrollView/ScrollView.js Adds the shouldDismissKeyboardOnTap prop and integrates it into "handled" responder-claim logic.
packages/react-native/Libraries/Components/ScrollView/ScrollView.d.ts Exposes the new prop in the public TypeScript ScrollViewProps definition.
packages/react-native/ReactNativeApi.d.ts Updates the generated API snapshot to reflect the new ScrollView prop.
packages/react-native/Libraries/Components/ScrollView/tests/ScrollView-shouldDismissKeyboardOnTap-test.js Adds unit tests for default claim, veto behavior, and non-consulted scenarios.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +36 to +59
async function renderScrollView(props: ScrollViewProps) {
let testRenderer;
await ReactTestRenderer.act(() => {
testRenderer = ReactTestRenderer.create(<ScrollView {...props} />);
});

const instance = (testRenderer as $FlowFixMe).root.find(
node => node.instance?._handleStartShouldSetResponder != null,
).instance as $FlowFixMe;

return instance;
}

describe('shouldDismissKeyboardOnTap', () => {
beforeEach(() => {
// Simulate a focused text input with an open soft keyboard.
TextInputState.registerInput(fakeTextInput);
TextInputState.focusInput(fakeTextInput);
});

afterEach(() => {
TextInputState.blurInput(fakeTextInput);
TextInputState.unregisterInput(fakeTextInput);
});

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 10, 2026
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Aug 10, 2026
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 Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants