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>
Related
I have made a custom button and below is the code.
export class MenuItems extends Component {
constructor(props) {
super(props);
this.state = {
loading: true
};
}
render() {
let { navigation, listingname, imagesource,} = this.props;
return (
<View >
<TouchableOpacity
onPress={this.props.onPress}
style={[styles.menuStyle]}>
<View style={{ flexDirection: 'row', }}>
<Image source={imagesource} style={[styles.menuItemIcon,{tintColor:'black'}]} />
<Text style={[styles.menuTextstyle]}>{listingname} </Text>
</View>
</TouchableOpacity>
</View>
);
}
}
export default MenuItems;
Now I have reused it with different value and images . I want to change the tint color and text color of the custom button to blue . Below is the code.
\<MenuItems listingname="Logout"
onPress={() => {
this.RBSheet.close();
// this.props.navigation.replace('HomeApp', { screen: 'Home' })
// navigation.dispatch(StackActions.popToTop());
// reset Notification counter
this.props.notifyCountrUpdtHndlr(0)
AuthHelpers.logout(this.props.navigation, true);
}}
imagesource ={IMAGE.LOGOUT_ICO}/>
</View>
I want the image color in blue using tint color and text color of the component in blue. kindly provide the solution and correct the code.
Use style
const StyledImage = ({style}) =>
<Image
style={{width: 20, height: 20, ...style}}
...
/>
<StyledImage style={{tintColor: 'blue'}} />
or custom prop
const TintedImage = ({tintColor}) =>
<Image
style={{width: 20, height: 20, tintColor: tintColor}}
...
/>
<TintedImage tintColor='red' />
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>
Below is my login class code :
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
loggedIn: true,
}
handlePress = () => {
this.props.onHomeviewPress(this.state.data);
}
}
render() {
return (
<View style={styles.container}>
<Text style={{ color: "blue", fontSize: 28, marginLeft: 10 }}> Login</Text>
<TextInput style={styles.input}
underlineColorAndroid="transparent"
placeholder="Email"
placeholderTextColor="blue"
autoCapitalize="none"
/>
<TextInput style={styles.input}
underlineColorAndroid="transparent"
placeholder="Password"
placeholderTextColor="blue"
autoCapitalize="none"
/>
<Button
onPress={() => this.handlePress.bind(this)}
title="Login"
/>
</View>
);
}
}
HAVING PROBLEM IN HANDLEPRESS FUNCTION IS NOT WORKING GIVING ERROR
undefined is not an object('_this2.handlepress.bind')
Please Help me solve this. Thanks in advance
Your handlePress function is defined in your constructor.
Move it outside and it will work
Also, you don't need to bind the function. Just onPress={this.handlePress} will work.
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)
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