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.

Slack input

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


Solution 1:

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}
      />
    );
  }
}

Solution 2:

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}
      />
    );
  }
}

Solution 3:

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