Home:ALL Converter>Mobile browser issue with textarea resize

Mobile browser issue with textarea resize

Ask Time:2019-01-31T08:14:31         Author:DanMad

Json Formatter

I am working in React.js and have textarea elements that dynamically expand and contract based on the size of the user's input. The intended functionality is as follows:

Working correctly in a desktop context

This works correctly in a desktop context. However, on any mobile or tablet in a modern browser (tested Safari, Chrome and Firefox) the textarea element only expands, it does not contract when content is deleted.

At first I thought it might have something to do with the onChange handler I was employing, however, the same issue remains when swapping it out with an onInput handler. So I believe the issue resides in the resize() method.

Does anyone have an idea of why I'm experiencing this issue?

I have created a style-free fiddle to share with you the basic functionality. Interestingly, the bug doesn't occur in the JSFiddle simulator on a mobile device, but if you take the same code and put it in another react environment, the bug occurs on a mobile device in modern browsers.

class Application extends React.Component {
  render() {
    return (
      <div>
        <Textarea value="This is a test" maxLength={500}/>
      </div>
    );
  }
}


class Textarea extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      value: this.props.value
        ? this.props.maxLength && this.props.maxLength > 0
          ? this.props.value.length < this.props.maxLength
            ? this.props.value
            : this.props.value.substring(0, this.props.maxLength)
          : this.props.value
        : '',
      remaining: this.props.value
        ? this.props.value.length < this.props.maxLength
          ? this.props.maxLength - this.props.value.length
          : 0
        : this.props.maxLength
    };

    this.textAreaRef = React.createRef();
    
    this.textAreaHeight = null;
    this.textAreaoffSetHeight = null;
  }
  
  
  componentDidMount() {
    window.addEventListener('resize', this.resize);
    this.resize();
  }
  
  componentWillUnmount() {
    window.removeEventListener('resize', this.resize);
  }
  
  handleChange = event => {
    const target = event.target || event.srcElement;

    this.setState({
      value: target.value,
      remaining: target.value
        ? target.value.length < this.props.maxLength
          ? this.props.maxLength - target.value.length
          : 0
        : this.props.maxLength
    });

    this.resize();
  };
  
  resize = () => {
    const node = this.textAreaRef.current;

    node.style.height = '';

    const style = window.getComputedStyle(node, null);

    let heightOffset =
      parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);

    this.textAreaoffSetHeight = node.offsetTop;

    this.textAreaHeight = node.scrollHeight + heightOffset;

    node.style.height = this.textAreaHeight + 'px';

    this.resizeBorder();
    this.resizeParentNode();
  };

  resizeBorder = () => {
    const textAreaSize = this.textAreaHeight;
    const node = this.textAreaRef.current;
    const borderNode = node.parentNode.querySelector(
      '.textarea__border'
    );
    
    if (borderNode !== null) {
      borderNode.style.top =
        this.textAreaoffSetHeight + textAreaSize - 1 + 'px';
    }
  };

  resizeParentNode = () => {
    const node = this.textAreaRef.current;
    const parentNode = node.parentNode;
    
    if (parentNode !== null) {
      parentNode.style.height = this.textAreaHeight + 40 + 'px';
    }
  };

    render() {
    return (
      <div className={'textarea'}>
        <textarea
          ref={this.textAreaRef}
          className={
            !this.state.value
              ? 'textarea__input'
              : 'textarea__input active'
          }
          value={this.state.value}
          maxLength={
            this.props.maxLength && this.props.maxLength > 0 ? this.props.maxLength : null
          }
          onChange={this.handleChange}
        />
        <div className={'textarea__message'}>
            {this.state.remaining <= 0
              ? `You've reached ${this.props.maxLength} characters`
              : `${this.state.remaining} characters remaining`}
          </div>
      </div>
    );
    }
}


ReactDOM.render(
  <Application />,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<main id="app">
    <!-- This element's contents will be replaced with your component. -->
</main>

Author:DanMad,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/54451545/mobile-browser-issue-with-textarea-resize
yy