1

I'm working on an app that has a reusable component that generates text areas when needed. This component receives an onChange function as a prop from its parent with the prop name onChange. The existing code uses a textarea element that has a consistent height, and this textarea triggers the onChange function without issue.

I am now working on getting the area to grow vertically instead of adding an overflow bar, and have replaced the textarea tag with a div, which allows the autogrowth to work as expected. However, the div tag will no longer trigger the onChange prop that the textarea element triggered without issue. I'm able to confirm that the onChange prop carries the same function over, but I'm stumped as to why it won't work. I was wondering if there is something that I'm missing in my code, or if I'm misunderstanding about how onChange functions work within React. I've pasted the original code and my best guess at what the updated code should look like, although I've tried multiple changes on the div.

Thanks in advance for any help on this!

Original textarea code:

<textarea className={textAreaStyle} {...textareaProps} rows={rows} />

Updated div code:

      <div
        className={textAreaStyle}
        rows={rows}
        contentEditable="true"
        {...textareaProps}
        onChange={props.onChange}
      >            
        {value}
      </div>

Update 1: I've tried replacing the line onChange={props.onChange} with onInput={props.onChange}, and now the function is being hit, but the actual state isn't being updated. Seeing if I can fix the state not being updated to resolve this issue.

Daniel
  • 155
  • 2
  • 12
  • 1
    the variable passed to the onChange atribute, is it in the current scope? If not, I assume you would need to use this, as props are normally function/class scoped. use onChange={this.props.onChange} – David Casanellas Sep 19 '18 at 15:01
  • I double checked and it is in the current scope. If I console.log the props.onChange value then the expected function is returned. – Daniel Sep 19 '18 at 15:06
  • 1
    try onChange={() => props.onChange}, this will execute and return the function as you say it does when console logging – David Casanellas Sep 19 '18 at 15:10
  • unfortunately making that change didn't have any impact on the div, although that does still work when it's a textarea element. – Daniel Sep 19 '18 at 15:20
  • makes sense ... wrap the textarea with a div and set the onchange on the textarea so you can fix the next thing ;) – David Casanellas Sep 19 '18 at 15:26
  • 1
    that does fix the functionality issue. however, by making this change, the autogrowth on the text area's height won't work. i'm trying to find a way to get the autogrowth on the height AND the onChange function to trigger, so far i can only do one or the other depending on the HTML element used. – Daniel Sep 19 '18 at 15:36

3 Answers3

1

Contenteditable behaviour and events differs from Texarea element so I suggest to take a look to out-of-the-box working component like:

https://github.com/lovasoa/react-contenteditable

If you are looking for autosize in textarea you can rely on UI Kit like Semantic UI React.

If you are looking for a custom solution there are still complete answers available on topic:

React.js: onChange event for contentEditable

Mosè Raguzzini
  • 15,399
  • 1
  • 31
  • 43
1

even added content-editable=true, div won't trigger onChange event, why dont you use textarea instead, use css to disable resize and overflow, otherwise you need to listen 'input' event for div, see contenteditable change events

anyway, I think all you need is https://www.npmjs.com/package/react-autosize-textarea

Allen Wong
  • 1,162
  • 1
  • 10
  • 15
0

I was able to fix this by using adding a small function in the parent component and then calling it as a prop in an onInput function, while leaving the onChange function set to props.onChange. The function was taken from the article below.

http://usefulangle.com/post/41/javascript-textarea-autogrow-adjust-height-based-on-content

Daniel
  • 155
  • 2
  • 12