How can i force TextInput to grow while multiline={false} on react native?

133 views Asked by At
<TextInput
  ref={inputRef}
  value={text}
  style={styles.textInput}
  returnKeyType="next"
  placeholder={"placeholder"}
  scrollEnabled={false}
  blurOnSubmit={false}
  onFocus={onFocusInput}
  textAlignVertical="center"
  onContentSizeChange={onChangeContentSizeChange}
  onChangeText={onInputChangeValue}
  onBlur={onInputBlur}
  onKeyPress={onInputKeyPress}
  onSubmitEditing={() => NextScript(id)}
  multiline={false}
  numberOfLines={5}
/>

The logic is I want onSubmitEditing to take me to next TextInput field and I need the text to wrap one much text is entered. If I enable multiline once enter key is pressed it goes to next line before going to the next input and that's what I am trying to avoid.

Is it possible to replace enter key totally with onSubmitEditing? Anytime I hit enter it attempts to enter newline before moving to next TextInput, so it creates a bad UI where the text is moving up slightly before repositioning then going to next line.

If I set blurOnSubmit to true, it stops but keyboard closes on submit. If I set multiline to false it stops but doesn't wrap text.

3

There are 3 answers

0
Michael Bahl On

I have created an example, onKeyPresswill allow you to focus the next textfield when enter key were hit.

import { Text, SafeAreaView, StyleSheet, TextInput } from 'react-native';

export default function App() {
  return (
    <SafeAreaView style={styles.container}>
      <TextInput
        multiline={true}
        placeholder={'PLACEHOLDER'}
        onKeyPress={(e) => {
          if (e.nativeEvent.key == 'Enter') {
            console.log('ENTER');
            //focusNextTextField();
          }
        }}
        style={{ borderColor: '#000000', borderWidth: 1 }}
      />
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignContent: 'center',
    padding: 8,
  },
});

1
Bharath-CODER On

I'm also facing the same issues. Later, I found the solution.

Custom Text Input Handling: You'll need a custom logic to handle the text input and its behavior upon pressing the 'Enter' key. Instead of relying on the default behavior of multiline, you'll control the text wrapping and navigation to the next input field programmatically.

Replace Enter Key with onSubmitEditing: To override the default behavior of the 'Enter' key, you can use the onKeyPress event. Detect when the 'Enter' key is pressed and programmatically trigger the onSubmitEditing function.

Maintain Text Wrapping: Since multiline={false} disables automatic text wrapping, you'll need to implement a method to manually handle text wrapping based on the input's content size or character count.

Here's a conceptual example of how you might implement this:

import React, { useState, useRef } from 'react';
import { TextInput, StyleSheet } from 'react-native';

const CustomTextInput = () => {
  const [text, setText] = useState('');
  const nextInputRef = useRef(null);

  const onInputKeyPress = (e) => {
    if (e.nativeEvent.key === 'Enter') {
      // Replace the Enter key functionality
      // Call the function you would have in onSubmitEditing
      handleEnterKeyPress();
    }
  };

  const handleEnterKeyPress = () => {
    // Logic to navigate to next TextInput
    // Focus the next input field
    if (nextInputRef.current) {
      nextInputRef.current.focus();
    }

    // Additional logic if needed to handle text wrapping
  };

  return (
    <TextInput
      value={text}
      style={styles.textInput}
      onChangeText={setText}
      onKeyPress={onInputKeyPress}
      blurOnSubmit={false} // prevent keyboard from closing
      // other props
    />
  );
};

const styles = StyleSheet.create({
  textInput: {
    // styling for your text input
  },
});

export default CustomTextInput;
0
Bala Vigness On

Instead try using this fully customizable TextInput component which I have used for past couple of years ,

import { StyleSheet, Text, TextInput, View, TouchableOpacity, Image } from 'react-native';
import React, { useEffect, useState } from 'react';
import { colors, fonts, images } from '../constants';

const InputText = ({
  error,
  labelName,
  labelChild,
  value,
  placeholder,
  onSubmitEditing,
  onChangeText,
  keyboardType,
  secureTextEntry,
  multiline,
  returnKeyType,
  autoFocus,
  placeholderTextColor,
  onBlur,
  errorText,
  inputref,
  inlineImageLeft,
  autoCorrect,
  style,
  onFocus,
  editable,
  maxLength,
  autoCapitalize,
  extraStyle
}) => {
  const [isFocused, setIsFocused] = useState(false);
  const [isPasswordVisible, setIsPasswordVisible] = useState(false);
  const [errorBorderColor, setErrorBorderColor] = useState(colors.lightGreen);

  useEffect(() => {
    setErrorBorderColor(error ? colors.errRed[0] : colors.lightGreen);
  }, [error]);

  const handleTogglePasswordVisibility = () => {
    setIsPasswordVisible(!isPasswordVisible);
  };
  const handleFocus = () => {
    setIsFocused(true);
  };
  const handleBlur = () => {
    setIsFocused(false);
  };
  return (
    <View style={styles.container}>
      <Text style={styles.label}>{labelName} <Text style={{ color: 'red' }}>{labelChild}</Text></Text>
      <View style={[styles.inputContainer, { borderColor: errorBorderColor }, extraStyle]}>
        <TextInput
          selectionColor={colors.green}
          ref={inputref}
          value={value}
          onChangeText={onChangeText}
          onSubmitEditing={onSubmitEditing}
          autoFocus={autoFocus}
          multiline={multiline}
          secureTextEntry={secureTextEntry && !isPasswordVisible}
          placeholder={placeholder}
          keyboardType={keyboardType}
          returnKeyType={returnKeyType}
          placeholderTextColor={placeholderTextColor}
          style={[styles.input, style]}
          onBlur={onBlur}
          onFocus={handleFocus}
          inlineImageLeft={inlineImageLeft}
          autoCorrect={autoCorrect}
          editable={editable}
          maxLength={maxLength}
          autoCapitalize={autoCapitalize}
        />
        {placeholder === "password" && isFocused && (
          <TouchableOpacity style={styles.iconContainer} onPress={handleTogglePasswordVisibility}>
            <Image
              source={isPasswordVisible ? images.eyeOpen : images.eyeClose}
              style={styles.icon}
            />
          </TouchableOpacity>
        )}
      </View>
      {error && (
        <View style={styles.errorContainer}>
          <Text style={styles.errorText}>{errorText}</Text>
        </View>
      )}
    </View>
  );
};

export default InputText;

const styles = StyleSheet.create({
  container: {
    alignItems: 'flex-start',
  },
  inputContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    borderWidth: 1,
    borderRadius: 15,
    paddingRight: 10,
    overflow: 'hidden',
  },
  input: {
    flex: 1,
    height: 45,
    fontSize: 18,
    fontFamily: fonts.Regular,
    includeFontPadding: false,
    color: colors.placeholder,
    paddingLeft: 10,
  },
  label: {
    fontSize: 14,
    marginBottom: 10,
    color: colors.black,
    fontWeight: '500',
  },
  iconContainer: {
    padding: 8,
  },
  icon: {
    width: 20,
    height: 20,
  },
  errorContainer: {
    height: 20,
    marginTop: 5,
  },
  errorText: {
    fontSize: 12,
    color: 'red',
    marginTop: 5,
    alignSelf: 'flex-start',
  },
});

You can import this and use it in your parent component.