Skip to content

[General] Allow gesture detector to have multiple children#3981

Merged
j-piasecki merged 5 commits intomainfrom
@jpiasecki/detector-multiple-children
Mar 2, 2026
Merged

[General] Allow gesture detector to have multiple children#3981
j-piasecki merged 5 commits intomainfrom
@jpiasecki/detector-multiple-children

Conversation

@j-piasecki
Copy link
Copy Markdown
Member

Description

Updates GestureDetector to accept more than a single child when using gestures other than native.

On native platforms, this is done by changing the layout of the detector node from matching its only child to calculating the bounding box of all children. The logic on Android needed to be updated so it tries to hit test every detector child instead of just the first one.

On web, this is done similarly, but since the detector node doesn't produce a box, the bounding box is calculated dynamically. This needed some updates in the custom findNodeHandle implementation to stop at display: contents nodes which have more than one child.

Test plan

import React from 'react';
import { StyleSheet, View } from 'react-native';
import { GestureDetector, useTapGesture } from 'react-native-gesture-handler';

export default function EmptyExample() {
  const tapGesture = useTapGesture({
    onActivate: () => {
      console.log('Tapped');
    },
  });

  return (
    <View style={styles.container}>
      <GestureDetector gesture={tapGesture} enableContextMenu={true}>
        <View style={styles.box} />
        <View style={styles.box} />
      </GestureDetector>
    </View>
  );
}

const styles = StyleSheet.create({
  box: {
    width: 100,
    height: 100,
    backgroundColor: 'red',
  },
  container: {
    gap: 32,
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

And example apps

Copilot AI review requested due to automatic review settings February 18, 2026 08:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request enables GestureDetector to accept multiple children for non-native gesture handlers, extending functionality beyond the previous single-child limitation. The implementation calculates bounding boxes that encompass all children across web, iOS, and Android platforms, while maintaining the restriction that native gesture handlers can only be attached to a single child view.

Changes:

  • Implemented bounding box calculation for multiple children on web (using display: contents elements), iOS/Android native shadow nodes, and Android hit testing
  • Added validation to prevent attaching native gesture handlers when multiple children are present
  • Refactored web delegate code to use a centralized style-setting helper method
  • Updated findNodeHandle on web to stop traversal at display: contents nodes with multiple children
  • Removed duplicate child count validation checks in the web detector component

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/react-native-gesture-handler/src/web/utils.ts Added getEffectiveBoundingRect function to calculate bounding box for display: contents elements with multiple children
packages/react-native-gesture-handler/src/web/tools/PointerEventManager.ts Updated to use new getEffectiveBoundingRect utility
packages/react-native-gesture-handler/src/web/tools/GestureHandlerWebDelegate.ts Refactored style-setting code into setViewStyle helper and updated to use getEffectiveBoundingRect
packages/react-native-gesture-handler/src/v3/detectors/HostGestureDetector.web.tsx Added validation for native handlers with multiple children and removed duplicate single-child checks
packages/react-native-gesture-handler/src/findNodeHandle.web.ts Updated to stop traversal at display: contents nodes with multiple children
packages/react-native-gesture-handler/shared/shadowNodes/.../RNGestureHandlerDetectorShadowNode.cpp Implemented bounding box calculation for multiple children and adjusted child positions relative to detector origin
packages/react-native-gesture-handler/apple/RNGestureHandlerDetector.mm Added assertions to prevent multiple children when native handlers are attached
packages/react-native-gesture-handler/android/.../RNGestureHandlerDetectorView.kt Added assertions to prevent multiple children when native handlers are attached
packages/react-native-gesture-handler/android/.../GestureHandler.kt Updated hit testing logic to check all children instead of just the first one

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

@akwasniewski akwasniewski left a comment

Choose a reason for hiding this comment

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

If we allow this, I think we should add a style prop to the detector which would be applied to the underlying view.

@j-piasecki
Copy link
Copy Markdown
Member Author

j-piasecki commented Feb 19, 2026

@akwasniewski That would defeat the purpose of calculating the bounding box. If someone sets width and height on the detector, which is different from the bbox, which one should be used?

It could also be confusing - in the example from the PR description, there's a gap between the two detector children. Gestures ARE NOT recognized on that gap. If the gesture detector had a background set, it could be understood as a surface for handling gestures.

It's possible to accomplish that in this approach by wrapping children with a view and styling that. If we went with styling the detector, I'm not sure the current behavior is easily replicable.

@akwasniewski
Copy link
Copy Markdown
Contributor

@akwasniewski That would defeat the purpose of calculating the bounding box. If someone sets width and height on the detector, which is different from the bbox, which one should be used?

It could also be confusing - in the example from the PR description, there's a gap between the two detector children. Gestures ARE NOT recognized on that gap. If the gesture detector had a background set, it could be understood as a surface for handling gestures.

It's possible to accomplish that in this approach by wrapping children with a view and styling that. If we went with styling the detector, I'm not sure the current behavior is easily replicable.

Ok, you are right, it would overcomplicate things.

@j-piasecki j-piasecki requested a review from m-bert February 26, 2026 11:12
Copy link
Copy Markdown
Contributor

@m-bert m-bert left a comment

Choose a reason for hiding this comment

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

I can see one limitation that I'm not sure if we can get rid of - it is not possible to trigger gesture(s) on all views at the same time. e.g. in the test code if you tap both boxes at the same time, "tapped" will be displayed only once.

j-piasecki and others added 2 commits March 2, 2026 09:24
…m/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt

Co-authored-by: Michał Bert <63123542+m-bert@users.noreply.github.com>
@j-piasecki
Copy link
Copy Markdown
Member Author

I can see one limitation that I'm not sure if we can get rid of - it is not possible to trigger gesture(s) on all views at the same time. e.g. in the test code if you tap both boxes at the same time, "tapped" will be displayed only once.

Is that a limitation? IMO, it's expected that the gesture will not activate twice. If you need that, you can use two separate ones.

Copy link
Copy Markdown
Contributor

@m-bert m-bert left a comment

Choose a reason for hiding this comment

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

Is that a limitation? IMO, it's expected that the gesture will not activate twice. If you need that, you can use two separate ones.

I think this is something that one might expect since all views are under one detector. But I agree that in that case you should have separate gestures.

@j-piasecki j-piasecki merged commit cefb702 into main Mar 2, 2026
9 checks passed
@j-piasecki j-piasecki deleted the @jpiasecki/detector-multiple-children branch March 2, 2026 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants