Skip to content

[Web] TextInput callbacks#4117

Draft
m-bert wants to merge 3 commits intomainfrom
@mbert/textinput-web
Draft

[Web] TextInput callbacks#4117
m-bert wants to merge 3 commits intomainfrom
@mbert/textinput-web

Conversation

@m-bert
Copy link
Copy Markdown
Collaborator

@m-bert m-bert commented Apr 24, 2026

Caution

Similarly as iOS version, this will be blocked for now.

Description

To match native platforms behavior, TextInput should activate immediately on web. This PR also extracts type of underlying view into separate variable.

Test plan

Tested on the following code:
import { useState } from 'react';
import { StyleSheet, TextInput } from 'react-native';
import {
  GestureDetector,
  GestureHandlerRootView,
  TextInput as RNGHTextInput,
  useNativeGesture,
} from 'react-native-gesture-handler';

export default function App() {
  const [value, setValue] = useState('');

  const g = useNativeGesture({
    onBegin: () => {
      console.log('gesture begin');
    },
    onActivate: () => {
      console.log('gesture activate');
    },
    onUpdate: () => {
      console.log('gesture update');
    },
    onDeactivate: () => {
      console.log('gesture deactivate');
    },
    onFinalize: () => {
      console.log('gesture finalize');
    },
  });

  return (
    <GestureHandlerRootView style={styles.container}>
      <TextInput
        value={value}
        onChangeText={setValue}
        style={[styles.input, { backgroundColor: 'red' }]}
      />
      <GestureDetector gesture={g}>
        <TextInput
          value={value}
          onChangeText={setValue}
          style={[styles.input, { backgroundColor: 'green' }]}
        />
      </GestureDetector>
      <RNGHTextInput
        onBegin={() => {
          console.log('gesture begin');
        }}
        onActivate={() => {
          console.log('gesture activate');
        }}
        onUpdate={() => {
          console.log('gesture update');
        }}
        onDeactivate={() => {
          console.log('gesture deactivate');
        }}
        onFinalize={() => {
          console.log('gesture finalize');
        }}
        style={[styles.input, { backgroundColor: 'blue' }]}
        value={value}
        onChangeText={setValue}
      />
    </GestureHandlerRootView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  input: {
    width: 200,
    height: 50,
  },
});

Copilot AI review requested due to automatic review settings April 24, 2026 10:24
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

Updates the web NativeViewGestureHandler to activate immediately for TextInput-like controls (to better match native behavior) and refactors control-role detection into a single controlType classification.

Changes:

  • Add ControlType enum and replace buttonRole/switchRole flags with controlType.
  • Activate the native view gesture immediately for detected text inputs on web (input/textarea).
  • Update downstream role checks (activate/move/isButton) to use controlType.

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

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

Updates the web implementation of NativeViewGestureHandler so that TextInput-like controls can activate immediately (aligning callback timing with native platforms), while also refactoring control-role tracking into a single typed field.

Changes:

  • Introduce a ControlType enum and replace buttonRole / switchRole flags with a single controlType.
  • Classify the underlying DOM element as Button, Switch, TextInput, or Other during init().
  • Update activation and pointer-move logic to use controlType, including immediate activation for detected text inputs.

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

Comment on lines +59 to +65
if (view.getAttribute('role') === 'button') {
this.controlType = ControlType.Button;
} else if (view.querySelector('input[role="switch"]') !== null) {
this.controlType = ControlType.Switch;
} else if (view.matches('input:not([role]):not([type]), textarea')) {
this.controlType = ControlType.TextInput;
} else {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I don't think think we need this, at least for now. Maybe we can add it in the future if it's necessary.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Input type will be used often since it changes what type of keyboard is shown on mobile.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Okay, you've got a point. But in that case, do we want to consider only text inputs, or also others, like number? I could be biased since this PR was specifically about TextInput, but now I'm not sure which behavior is correct.

Also if we want other types to activate on start, I think that TextInput role doesn't fit anymore, maybe just Input would be better.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I mean, it doesn't really make sense for an email input to behave differently from a number input in this context.

I think that TextInput role doesn't fit anymore, maybe just Input would be better.

Why not? It's still TextInput component underneath, and when filtering over type we'd want the ones that result in a text input anyway.

@m-bert m-bert requested a review from j-piasecki April 24, 2026 11:19
@m-bert m-bert marked this pull request as draft April 27, 2026 08:21
@m-bert m-bert added the Postponed This PR is not being actively worked on, but might be useful in the future. label May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Postponed This PR is not being actively worked on, but might be useful in the future.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants