React Native TextInput auto grow when multilne - react-native

I want to create a TextInput which can grow automatically when it has multilines.
<TextInput
placeholder="Type Comment"
value={this.state.comment.value}
onChangeText={value => this.onChangeComment(value)}
onPress={() => this.uploadComment()}
multiline={true}
maxLength={200}
numberOfLines={5}
/>
How can I achieve this?

Think that the React Native team fixed it in current version (0.59) with the multiline prop.
This works for me
<TextInput
style={{
width: '90%',
borderColor: 'gray',
borderWidth: 1,
padding: 2,
}}
multiline
onChangeText={text => this.setState({ text })}
value={this.state.text}
/>

To implement auto grow multiline text input, you can adjust the height of the text input according to the content size in the textInput.
you can use onContentSizeChange prop in TextInput and call a function to increase/decrease the height of input.
Here is the quick example code
export default class YourComponent extends Component {
constructor (props) {
super(props);
this.state = {
newValue: '',
height: 40
}
}
updateSize = (height) => {
this.setState({
height
});
}
render () {
const {newValue, height} = this.state;
let newStyle = {
height
}
return (
<TextInput
placeholder="Your Placeholder"
onChangeText={(value) => this.setState({value})}
style={[newStyle]}
editable
multiline
value={value}
onContentSizeChange={(e) => this.updateSize(e.nativeEvent.contentSize.height)}
/>
)
}
}
OR
You might want to use react-native-auto-grow-textinput

With React Hooks
Just to add to Shivam's answer, here is the version with hooks:
import React, { useState } from 'react'
export default function MyTextInput(props) {
const [height, setHeight] = useState(42)
return <TextInput
style={styles.input, {height: height}}
onContentSizeChange={e => setHeight(e.nativeEvent.contentSize.height)} />
}

Use module for this
import {AutoGrowingTextInput} from 'react-native-autogrow-textinput';
return (
<AutoGrowingTextInput
style={styles.textInput}
placeholder={'Your Message'}
value={value}
/>
)
Link: https://www.npmjs.com/package/react-native-autogrow-textinput

Related

How to create outlined (focused) TextInput in React Native?

Here is my code:
<View style={styles.inputView} >
<TextInput
style={styles.TextInputStyleClass}
placeholder="Email"
placeholderTextColor="#003f5c"
onChangeText={text => this.setState({email:text})}/>
</View>
Here is textinput style
TextInputStyleClass:{
textAlign: 'auto',
height: 50,
borderWidth: 1,
borderColor: '#c2c2c2',
borderRadius: 5 ,
backgroundColor : "#ffffff"
}
I am new to React Native application development and I am trying to textinput outlined focus. But the textinput is not focused with the code which I wrote above. Also I have tried with textinput mode but nothing helped me.
How can I create textInput outlined focus?
try to use component state.
class textInput extends React.Component {
constructor(props) {
super(props);
this.state = { isFocus: false };
}
render() {
return (
<TextInput
onBlur={() => {
this.setState({ isFocus: false });
}}
onFocus={() => {
this.setState({ isFocus: true });
}}
style={this.isFocus ? { borderColor: 'red' } : { borderColor: 'green' }}
/>
);
}
}
you should add the mode='outlined'
<View style={styles.inputView} >
<TextInput
style={styles.TextInputStyleClass}
placeholder="Email"
mode='outlined'
placeholderTextColor="#003f5c"
onChangeText={text => this.setState({email:text})}
/>
</View>

TextInput is blank whenever I type in React Native

I stumbled upon this issue that whenever I type anything on the TextInput, there is no text being type, meaning its blank.
I am using typescript btw. Here's my FormInput code:
import React from 'react';
import {View, TextInput, StyleSheet} from 'react-native';
import {COLORS, FONTS} from '../../constants';
interface Props {
placeholderText: string;
labelValue: any;
}
const FormInput: React.FC<Props> = ({
placeholderText,
labelValue,
...restProps
}) => {
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder={placeholderText}
autoCorrect={false}
value={labelValue}
{...restProps}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
marginVertical: 35,
},
input: {
paddingVertical: 25,
paddingHorizontal: 20,
borderRadius: 50,
borderWidth: 2,
borderColor: COLORS.transparent,
backgroundColor: COLORS.lightGray,
...FONTS.body3,
color: COLORS.darkgray,
},
});
export default FormInput;
And I added it on my LoginScreen like this:
interface Props {
placeholder: string;
keyBoardType: string;
secureTextEntry: string;
buttonTitle: string;
}
interface State {
email: string;
password: string;
}
export default class LoginScreen extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
email: '',
password: '',
};
}
render() {
return (
<View style={styles.container}>
<SafeAreaView>
<View style={styles.logoContainer}>
<Image style={styles.logo} source={images.logo} />
</View>
<Text style={styles.loginText}>Login</Text>
<View style={styles.textInputContainer}>
<FormInput
placeholderText="Your email..."
keyBoardType="email-address"
autoCapitalize="none"
autoCorrect="none"
labelValue={this.state.email}
onChangeText={(userEmail: any) =>
this.setState({email: userEmail})
}
/>
<FormInput
placeholderText="Your password..."
secureTextEntry={true}
labelValue={this.state.password}
onChangeText={(userPassword: any) =>
this.setState({password: userPassword})
}
/>
<FormButton
buttonTitle="Login"
onPress={() => Alert.alert('hello')}
/>
</View>
</SafeAreaView>
</View>
);
}
}
When I started typing. It looks like this:
Any idea what's causing this?
From React Native documentation: Note that some props are only available with multiline={true/false}. Additionally, border styles that apply to only one side of the element (e.g., borderBottomColor, borderLeftWidth, etc.) will not be applied if multiline=true. To achieve the same effect, you can wrap your TextInput in a View:
So just add multiline prop to your FormInput
const FormInput = ({ placeholderText, labelValue, ...restProps }) => {
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder={placeholderText}
autoCorrect={false}
multiline // -- this one!
value={labelValue}
{...restProps}
/>
</View>)}

Change the color of Button when onFocus input

Good Morning , I tried a simple component with react-native that changes the color of my button while onFocus().I can't find how to change the color . Here is my component . Have you any ideas ?
import React, {Component} from 'react';
import {
StyleSheet,Text, View, Button,
} from 'react-native';
export default class App extends Component {
render() {
return (
<View style={styles.inputContainer}>
<TextInput
maxHeight={200}
style={styles.textInput}
ref={(r) => {
this.textInputRef = r;
}}
placeholder={'Message'}
underlineColorAndroid="transparent"
onFocus={()=>{/*Here i awant to change the color of Button }}
testID={'input'}
/>
<Button color="transparent" id="ScanButton"
onPress={() => this.setState({text: 'Placeholder Text'})}
title="Scan Barcode"
/>
</View>
)}
First Initialize your variable
constructor(props) {
super(props);
this.state = {
isFocus: false
}
}
In your TextInput add two props onFocus() and onBlur()
<TextInput
maxHeight={200}
style={styles.textInput}
ref={(r) => {
this.textInputRef = r;
}}
placeholder={'Message'}
underlineColorAndroid="transparent"
onBlur={() => this.onBlur()}
onFocus={() => this.onFocus()}
testID={'input'}
/>
add two methods in your class to change the state
onFocus() {
this.setState({
isFocus: true
})
}
onBlur() {
this.setState({
isFocus: false
})
}
and your button style will be like that
<Button
color={this.state.isFocus ? 'red' : 'green'}
id="ScanButton"
onPress={() => this.setState({text: 'Placeholder Text'})}
title="Scan Barcode"
/>
style={{color: this.props.focused ? '#8B327C' :'#3F8B99'}}
try something like this

Enable paste and selection within TextInput - React Native

I am trying to implement copy and paste within my TextInput but cant seem to achieve it. I was expecting a tooltip when I long-pressed on my TextInput, however nothing happens.
I know about Clipboard and would know how to implement it, but I cant seem to get the paste option to pop to the user.
Any ideas how I can achieve this?
<TextInput
maxLength={29}
autoCapitalize={'characters'}
numberOfLines={1}
keyboardType={'default'}
underlineColorAndroid='transparent'
autoCorrect={false}
value={IBAN.printFormat(this.state.ibanInput)}
returnKeyType={'next'}
onChangeText={iban => this.verifyIban(iban)}
style={[{ borderWidth: 1, borderRadius: 2, height: '100%', width: '100%', textAlign: 'center', fontSize: width/24 },
]}
/>
Here is the answer if copy/paste does not work for TextInput - React Native
Step 1) In Contructor take testWidth property and assign value as '99%'.
e.g.
this.state = {testWidth: '99%' };
Step 2) In componentDidMount change testWidth value like '100%', do it inside of setTimeout.
e.g.
setTimeout(() => {
this.setState({ testWidth: '100%' })
}, 100)
Step 3) In style attribute of TextInput add dynamic width which we declare in Contractor, e.g
<TextInput style={{ width: this.state.testWidth }} />
Here is the full code: (Just copy and paste in App.js file).
import React, { Component } from 'react';
import { TextInput, View } from 'react-native';
export class App extends Component {
constructor(props) {
super(props);
this.state = { text: '', testWidth: '99%' };
}
componentDidMount() {
setTimeout(() => {
this.setState({ testWidth: '100%' })
}, 100)
}
render() {
return (
<View style={{ marginTop: 50 }}>
<TextInput
style={{ width: this.state.testWidth }}
placeholder="Type here to translate!"
onChangeText={(text) => this.setState({ text })}
value={this.state.text}
/>
</View>
);
}
}
Good Luck
Have a look at this code!: https://github.com/facebook/react-native/issues/18926#issuecomment-490541013
<ScrollView
contentContainerStyle={Styles.contentContainerStyle}
keyboardShouldPersistTaps="handled"
removeClippedSubviews={false}>
<KeyboardAvoidingView>
<Text style={Styles.labelPageTitle}>
{'bla bla bla'}
</Text>
<Text>
{'bla bla bla'}
</Text>
<TextInput
onChangeText={text => this.setState({ title: text })}
style={Styles.textInput}
value={title}
/>
</KeyboardAvoidingView>
use RN-clipboard
const text = await Clipboard.getString()
setCopiedText(text)

How would I grow <TextInput> height upon text wrapping?

I'm trying to create a <TextInput> that can grow in height when the text wraps to the next line, similar to how Slack's message input grows with the text up to a point.
I have the multiline prop set, so it is wrapping but the docs don't seem to mention any event regarding wrapping, and the only thing I can think of is a really hacky strategy to character count to figure out when to increase height of the input. How would I accomplish this?
https://facebook.github.io/react-native/docs/textinput.html
Thanks to react-native doc: https://facebook.github.io/react-native/docs/textinput.html
You can do something like that:
class AutoExpandingTextInput extends React.Component {
state: any;
constructor(props) {
super(props);
this.state = {text: '', height: 0};
}
render() {
return (
<TextInput
{...this.props}
multiline={true}
onChange={(event) => {
this.setState({
text: event.nativeEvent.text,
height: event.nativeEvent.contentSize.height,
});
}}
style={[styles.default, {height: Math.max(35, this.state.height)}]}
value={this.state.text}
/>
);
}
}
0.46.1 or higher: (as explained by Nicolas de Chevigné)
class AutoExpandingTextInput extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', height: 0};
}
render() {
return (
<TextInput
{...this.props}
multiline={true}
onChangeText={(text) => {
this.setState({ text })
}}
onContentSizeChange={(event) => {
this.setState({ height: event.nativeEvent.contentSize.height })
}}
style={[styles.default, {height: Math.max(35, this.state.height)}]}
value={this.state.text}
/>
);
}
}
Since React Native 0.46.1 :
contentSize property was removed from TextInput.onChange event
If you use this version, you can deal with onContentSizeChange prop
From the Jérémy answer, we have
class AutoExpandingTextInput extends React.Component {
constructor(props) {
super(props);
this.state = {
text: '',
height: 0
};
}
render() {
return (
<TextInput
{...this.props}
multiline={true}
onChangeText={(text) => {
this.setState({ text })
}}
onContentSizeChange={(event) => {
this.setState({ height: event.nativeEvent.contentSize.height })
}}
style={[styles.default, {height: Math.max(35, this.state.height)}]}
value={this.state.text}
/>
);
}
}
You should just set a maxHeight property in the style:
<TextInput multiline style={{maxHeight: 80}} />
Demo here: https://snack.expo.io/#yairopro/multiline-input-with-max-height
My answer is to use onContentSizeChange and numberOfLines props in TextInput, of course turn on multiline, this is my solution:
let numOfLinesCompany = 0;
<TextInput
...
multiline={true}
numberOfLines={numOfLinesCompany}
onContentSizeChange={(e) => {
numOfLinesCompany = e.nativeEvent.contentSize.height / 18;
}}
/>
18 is the height of text, propably depends on fontSize
Shoutout to Jérémy Magrin for his answer. This is his code but refactored to use functional components and hooks.
Note, you might need to use minHight instead of height in some RN versions.
const AutoExpandingTextInput = ({...props})=> {
const [text, setText] = useState('');
const [height, setHeight] = useState();
return (
<TextInput
{...props}
multiline={true}
onChangeText={text => {
setText(text);
}}
onContentSizeChange={event => {
setHeight(event.nativeEvent.contentSize.height);
}}
style={[styles.default, {height: height}]}
value={text}
/>
);
}
<TextInput multiline style={{maxHeight: ...}} />
In the hooks.
const [inputHeight, setInputHeight] = React.useState(40);
<TextInput
multiline
style={{ inputHeight }}
onContentSizeChange={(event) => {
setInputHeight(event.nativeEvent.contentSize.height);
}}
/>
What I have done is set View for the Input max height, for example:
messageBox: {
maxHeight: 110,
width: '80%',
borderRadius: 10,
padding: 10,
backgroundColor: Color.White},
and set the Input to multiline:
<View style={[styles.messageBox, styles.managerMsg]}>
<Input
allowFontScaling={false}
name="notes"
blurOnSubmit={false}
onChangeText={notes => console.log(notes)}
returnKeyType="go"
onSubmitEditing={() => Keyboard.dismiss()}
multiline
/>
</View>
This "Input" is just a simple custom component that receives all Props.
You might as well try something like this.
<TextInput style={[styles.inputs,{height: Math.max(35, this.state.height)}]}
placeholder="Write a message..."
multiline={true}
onChangeText={(msg) => this.setState({ text: msg })}
onSubmitEditing={Keyboard.dismiss}
onContentSizeChange = {() => this.scrollView.scrollToEnd({animated:true})}
/>
style.inputs
inputs: {
minHeight:40,
marginLeft: 16,
paddingTop: 10,
overflow:'hidden',
padding: 15,
paddingRight: 25,
borderBottomColor: '#000000',
flex: 1,
position: 'absolute',
width: '100%',
},
When the text grows beyond one line, a scroll view is created within the text input field and scrolls automatically to the bottom. This actually doesn't increase the text input height when the content grows, instead, a scroll view is created within the input field. Serves the purpose.
I'm posting my solution as others didn't work for me(the text input size grew behind the keyboard, and there were text-overflow issues).
Hence, for anyone who faced a similar problem as I did, this would hopefully work for you.
<View style={{flex:1}}>
<TextInput
multiline={true} />
</View>
You can also use onChangeText to set the TextInput height like so.
const textHeight = 19 //fontsize of the text
<TextInput
style={[styles.input,
{height:Math.max(40,inputHeight)}]}
onChangeText= {text => {
const height = text.split("\n").length
setInputHeight(height * textHeight)
}}
multiline
/>
Just use multiline={true} no need to set height. check the following
<SafeAreaView style={{flex:1, backgroundColor:"#F8F8F9"}}>
<ScrollView style={{flex:1}}>
{
this.state.data && <CommentListView data={this.state.data} onReplyClick={this.onReplyClick}/>
}
</ScrollView>
<View style={{bottom:Platform.OS=="ios" ? this.state.keyboardHeight : 0, flexDirection:"row", alignItems:"flex-end", padding:10}}>
<TextInput
multiline={true}
style={{flex:3, backgroundColor:"#EFEFEF", borderRadius:5, padding:10}}
value={this.state.comment}
onChangeText={(text)=> this.setState({comment:text})}
/>
<TouchableOpacity style={{flex:1}} onPress={()=> this.submit()}>
<Text style={{padding:13, color:"#fff", textAlign:"center", fontWeight:"bold", backgroundColor:"#00394D", borderWidth:1, borderColor:"#00FFEE", borderRadius:5, overflow: "hidden"}}>Post</Text>
</TouchableOpacity>
</View>
</SafeAreaView>