Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/components/TextInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {ForwardedRef} from 'react';
import React, {useEffect, useRef} from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import useThemeStyles from '@hooks/useThemeStyles';
import * as Browser from '@libs/Browser';
import {isMobileChrome} from '@libs/Browser';
import DomUtils from '@libs/DomUtils';
import Visibility from '@libs/Visibility';
import BaseTextInput from './BaseTextInput';
Expand All @@ -15,6 +15,7 @@ function TextInput(props: BaseTextInputProps, ref: ForwardedRef<BaseTextInputRef
const styles = useThemeStyles();
const textInputRef = useRef<HTMLFormElement | null>(null);
const removeVisibilityListenerRef = useRef<RemoveVisibilityListener>(null);
const isAutoFocusEnabled = typeof ref === 'function' || props.autoFocus;

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.

@martasudol Could you help to detail the RCA and how this change will fix the problem?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The main issue was likely that ref could be a function when using the useAutoFocusInput hook, which might have caused unexpected behavior in the keyboard visibility check.

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.

But why useAutoFocusInput doesn't work on this case?

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.

For clear, in useAutoFocusInput we already implemented a logic to auto focus the input

inputRef.current?.focus();

And I think we need to point out why it doesn't work on the physical devices

@martasudol martasudol Mar 25, 2025 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It seems that autofocus is triggered differently on iOS real devices compared to Android or simulators/emulators - timing and visibility behavior can vary quite a bit depending on the platform.

Anyway, I’ve just tested the latest version of the app on a real iOS device, and it looks like the issue is no longer reproducible - everything works as expected now.

Could you please re-test on your side and confirm whether the bug is still happening for you? 🙏 Looks like someone fixed this in the meantime :D

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.

I still can reproduce on Chrome on Iphone (with latest main)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You’re right - I was able to reproduce the issue in the browser on iOS as well.

My fix specifically addresses this problem, which only occurs in iOS browsers. The root cause is that React Native for Web doesn’t fully support autofocus for web iOS; a focus trigger is required for autofocus to work properly.

In our case, we use the useAutoFocusInput hook and then pass down the default props, which slightly changes how autofocus is triggered for iOS browsers. This difference in behavior is likely what caused the issue.


useEffect(() => {
let removeVisibilityListener = removeVisibilityListenerRef.current;
Expand All @@ -27,7 +28,7 @@ function TextInput(props: BaseTextInputProps, ref: ForwardedRef<BaseTextInputRef
}

removeVisibilityListener = Visibility.onVisibilityChange(() => {
if (!Browser.isMobileChrome() || !Visibility.isVisible() || !textInputRef.current || DomUtils.getActiveElement() !== textInputRef.current) {
if (!isMobileChrome() || !Visibility.isVisible() || !textInputRef.current || DomUtils.getActiveElement() !== textInputRef.current) {
return;
}
textInputRef.current.blur();
Expand Down Expand Up @@ -57,6 +58,7 @@ function TextInput(props: BaseTextInputProps, ref: ForwardedRef<BaseTextInputRef
<BaseTextInput
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
autoFocus={isAutoFocusEnabled}
ref={(element) => {
textInputRef.current = element as HTMLFormElement;

Expand Down