Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javascript/react dynamic height textarea (stop at a max)

What I'm trying to achieve is a textarea that starts out as a single line but will grow up to 4 lines and at that point start to scroll if the user continues to type. I have a partial solution kinda working, it grows and then stops when it hits the max, but if you delete text it doesn't shrink like I want it to.

This is what I have so far.

export class foo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      textareaHeight: 38
    };
  }

  handleKeyUp(evt) {
    // Max: 75px Min: 38px
    let newHeight = Math.max(Math.min(evt.target.scrollHeight + 2, 75), 38);
    if (newHeight !== this.state.textareaHeight) {
      this.setState({
        textareaHeight: newHeight
      });
    }
  }

  render() {
    let textareaStyle = { height: this.state.textareaHeight };
    return (
      <div>
        <textarea onKeyUp={this.handleKeyUp.bind(this)} style={textareaStyle}/>
      </div>
    );
  }
}

Obviously the problem is scrollHeight doesn't shrink back down when height is set to something larger. Any suggestion for how I might be able to fix this so it will also shrink back down if text is deleted?

like image 516
jcmitch Avatar asked Sep 08 '16 23:09

jcmitch


People also ask

How increase textarea height dynamically react?

To set the height of a text area dynamically with JavaScript and React, we can set the height of the text area when we type into it. to set the onKeyDown prop to the handleKeyDown function. In it, we set the height of the text area to the e. target.

How do I restrict textarea size?

To disable the resizing (drag thumb) just use resize: none; . To restrict size max(min)-width and height should do the trick. Show activity on this post. You can set the resize property as horizontal and vertical or set it as default(the user can stretch in both ways).

How do I stop textarea from expanding horizontally?

To prevent a text field from being resized, you can use the CSS resize property with its "none" value. After it you can use the height and width properties to define a fixed height and width for your <textarea> element.


1 Answers

ANOTHER SIMPLE APPROACH (without an additional package)

export class foo extends React.Component {
  handleKeyDown(e) {
    e.target.style.height = 'inherit';
    e.target.style.height = `${e.target.scrollHeight}px`; 
    // In case you have a limitation
    // e.target.style.height = `${Math.min(e.target.scrollHeight, limit)}px`;
  }

  render() {
    return <textarea onKeyDown={this.handleKeyDown} />;
  }
}

The problem when you delete the text and textarea doesn't shrink back is because you forget to set this line

e.target.style.height = 'inherit';

Consider using onKeyDown because it works for all keys while others may not (w3schools)

In case you have padding or border of top or bottom. (reference)

handleKeyDown(e) {
    // Reset field height
    e.target.style.height = 'inherit';

    // Get the computed styles for the element
    const computed = window.getComputedStyle(e.target);

    // Calculate the height
    const height = parseInt(computed.getPropertyValue('border-top-width'), 10)
                 + parseInt(computed.getPropertyValue('padding-top'), 10)
                 + e.target.scrollHeight
                 + parseInt(computed.getPropertyValue('padding-bottom'), 10)
                 + parseInt(computed.getPropertyValue('border-bottom-width'), 10);

    e.target.style.height = `${height}px`;
}

I hope this may help.

like image 116
Tatsu Avatar answered Oct 07 '22 19:10

Tatsu