Justin
Justin

Reputation: 317

React Native to limit lines in TextInput

If set multiline as true, React Native will accept unlimited lines in TextInput, there has maxLength but it just limits the maximum number of characters, so how to set maximum lines on TextInput?

Upvotes: 14

Views: 40157

Answers (8)

ObjectJosh
ObjectJosh

Reputation: 641

I was solving this same issue. Here's what I came up with. You can either remove the last trailing newline, or all of them. Both work differently, so use accordingly to how you want yours to function. I personally chose the remove last trailing newline alternative:

function onChangeText(text) {
    if (props.multiline) {
        const newlines = (text.match(/\n/g) || '').length + 1;
        if (newlines > MAX_LINES) {
            props.setState(text.replace(/\n$/, "")); // Remove last trailing newline
            // props.setState(text.replace(/\n+$/, "")); // Remove all trailing newlines
            return;
        }
    }
    props.setState(text);
    return;
};

Upvotes: 0

Irfan Khan
Irfan Khan

Reputation: 511

I solved the limit issue using maxHeight,numberOfLine and multiline prop

<TextInput placeholder="description here" numberOfLines={3} maxHeight={60} onChangeText={t => setDescription(t)} multiline={true} style={{ margin: 10, borderRadius: 20, padding: 5, borderWidth: 1 }} />

Upvotes: 1

Felipe R. Saruhashi
Felipe R. Saruhashi

Reputation: 1739

I created a simple version to extend the TextInput to give the maxLines feature.

import React, { Component } from "react";
import { TextInput } from "react-native";
import PropTypes from "prop-types";

export default class MultiLine extends Component {
  static propTypes = {
    maxLines: PropTypes.number
  };

  constructor(props) {
    super(props);
    this.state = {
      value: props.value || ""
    };
  }

  onChangeText = text => {
    const { maxLines, onChangeText } = this.props;
    const lines = text.split("\n");

    if (lines.length <= (maxLines || 1)) {
      onChangeText(text);
      this.setState({ value: text });
    }
 };

 render() {
   const { onChangeText, multiline, value, ...other } = this.props;
   return (
     <TextInput
       {...other}
       multiline={true}
       value={this.state.value}
       onChangeText={this.onChangeText}
     />
   );
 }
}

A example:

<Multiline
  value={this.state.testeText}
  maxLines={10}
  onChangeText={text => {
    this.setState({ testeText: text });                
  }}
/>

Upvotes: 7

Ricardo BM
Ricardo BM

Reputation: 11

numberOfLines doesn't nothing in android too

You can do something like this

In Component state

this.state = {height: 35};

In JSX TextInput declaration

style={[styles.default, {height: Math.min(Math.max(35, this.state.height),120)}]}

Upvotes: 0

David
David

Reputation: 1591

You can use maxHeight and minHeight to accept what you want. For standard text fontSize, giving maxHeight={60} will make TextInput scrollable after 3 lines. This is good for IOS - for Android you can use numberOfLines prop.

Upvotes: 16

I have implemented the following component for an app I'm the owner. It is tested only on a restricted environment, so it probably has to be adapted to your need. I am sharing here with the hope it helps the community.

react-native: 0.46.3

import React, { Component } from 'react'
import { TextInput, Platform } from 'react-native'

const iosTextHeight = 20.5
const androidTextHeight = 20.5
const textHeight = Platform.OS === 'ios' ? iosTextHeight : androidTextHeight

class TextInputLines extends Component {
  state = { height: textHeight * 2, lines: 1 }

  componentWillReceiveProps (nextProps) {
    if (nextProps.value === '') {
      this.setState({ height: textHeight * 2, lines: 1 })
    }
  }

  render () {
    const {style, value, placeholder, numberOfLines = 8, autoFocus = true, onChangeText} = this.props

    return (
      <TextInput
        style={[style, { height: this.state.height }]}
        multiline
        autoFocus={autoFocus}
        value={value}
        placeholder={placeholder}
        onChangeText={(text) => onChangeText(text)}
        onContentSizeChange={(event) => {
          const height = Platform.OS === 'ios'
            ? event.nativeEvent.contentSize.height
            : event.nativeEvent.contentSize.height - androidTextHeight
          const lines = Math.round(height / textHeight)
          const visibleLines = lines < numberOfLines ? lines : numberOfLines
          const visibleHeight = textHeight * (visibleLines + 1)
          this.setState({ height: visibleHeight, lines: visibleLines })
        }}
        underlineColorAndroid='transparent'
      />
    )
  }
}

export default TextInputLines

How to use:

import TextInputLines from './TextInputLines'

Within your render() method:

<TextInputLines
   style={textStyle}
   autoFocus={true}
   value={this.state.value}
   placeholder={textPlaceholder}
   onChangeText={onChangeText}
   numberOfLines={10}
/>

Upvotes: 4

Justin
Justin

Reputation: 317

It seems no props or packages to quickly implement checking number of lines, so I use javascript function match to get the number from TextInput, then if the number reach the max value, do something to limit it.

Upvotes: 0

klvs
klvs

Reputation: 1177

I don't think you can on iOS. As mentioned, Android has the prop numberOfLines. The closest I can think of would be to try to estimate the width of your input and limit the characters based on that dimension but it's my opinion that it may be a dark path to go down.

Should you choose to do so, someone was trying to get the number of lines here. A combination of the onLayout function to get the width of your TextInput and onChangeText to limit it might work.

Upvotes: 0

Related Questions