0

I'm trying to implement a simple script to manage resizing the textarea to fit the content. It works perfectly when adding content but every time I press the backspace key the scrollheight value increases by 3px!

document.querySelectorAll('textarea').forEach( element => {
  element.style.height = `${element.scrollHeight}px`
  element.addEventListener('input', event => {
    event.target.style.height = `${event.target.scrollHeight}px`
  })
})
/* style.css */
main, header {
  max-width: 600px;
  margin: auto;
}

textarea {
  font-family: 'Times New Roman', Times, serif;
  font-size: 1em;
  border-style: hidden;
  outline: none;
  padding: 0.1em;
  margin: none;
  resize: none;
  width: 80%;
  border-radius: 0.2em;
  border: 1px solid #EEE;
}

textarea:focus {
  border: 1px solid #DDD;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf8" />
    <meta name="viewport" content="width=device-width", initial-scale="1.0" />
    <title>Resizing Text Area</title>
    <link href="style.css" rel="stylesheet" type="text/css">
    <script type="module" src="./script.js" defer></script>
  </head>
  <body>
    <header>
      <h1>Resizing Text Area</h1>
    </header>
    <main>
      <p><textarea class="data p" id="article"></textarea></p>
    </main>
  </body>
</html>

Does anyone know the cause of this annoying behaviour?

Mark Tyers
  • 2,647
  • 4
  • 24
  • 47
  • Can you include CSS so that this can be tested out? I notice that when experimenting with your code the textbox resizes on every key stroke even if no scroll bar has been created. Is this intentional or should resizing only occur when the content grows such that it creates a scrollbar? – GenericUser Dec 31 '21 at 15:35
  • The CSS is not relevant to the question, I should have not included the link but I will add it here. The code show checked whenever the content changes but I'm open to any suggestion here. – Mark Tyers Dec 31 '21 at 15:43
  • What browser are you running this in? I'm on Chrome and it seems to have odd behavior. As it appears to me, the height of the textarea grows from a single character press. I suspect that whatever behavior you're seeing with backspace could be browser-specific. – GenericUser Dec 31 '21 at 15:49
  • The issue was first noticed in Safari however I get the same behaviour in Chrome. – Mark Tyers Dec 31 '21 at 15:54
  • 1
    _"backspace increases value of scrollheight"_ **False.** Any key does that. – HoldOffHunger Dec 31 '21 at 16:03
  • OK, but why should this be the case? I'm struggling to understand why pressing a key on the same line in the textarea changes the scrollHeight. – Mark Tyers Dec 31 '21 at 16:04

3 Answers3

1

I finally figured out what the problem was (and how to fix it). The solution was to set the height of the textarea to auto before resizing it to fit the contents (see below). I would be curious to know why this works...

/* script.js */

console.log('script loaded')

document.querySelectorAll('textarea').forEach( element => {
  element.style.height = `${element.scrollHeight}px`
  element.addEventListener('input', event => {
    event.target.style.height = 'auto' // added this line
    event.target.style.height = `${event.target.scrollHeight}px`
  })
})
Mark Tyers
  • 2,647
  • 4
  • 24
  • 47
  • 1
    This gives some explanation on how `auto` works here: https://www.w3.org/TR/CSS2/visudet.html#root-height. From what I gather here the `auto` value for the height of an element will trim the unused area or expand if needed so that all content is visible and any unused portion is trimmed. – GenericUser Dec 31 '21 at 19:49
0

Explaining this requires understanding the box model. In this case, you are using scrollHeight, which includes borders and padding of the element - this is why the height is incrementing on any change.

For this I'm assuming you just want the textarea to expand when it's about to overflow, i.e. a scrollbar appears. Rather than having it change on every input event, check only if the scrollHeight exceeds the clientHeight. Whenever that occurs, increase the rows of the textarea in order to expand it.

document.querySelectorAll('textarea').forEach(element => {
  element.addEventListener('input', event => {
    while (event.target.scrollHeight > event.target.clientHeight) {
      event.target.rows++;
    }
  });
})
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf8" />
  <meta name="viewport" content="width=device-width" , initial-scale="1.0" />
  <title>Data Management</title>
  <link href="style.css" rel="stylesheet" type="text/css">
  <script type="module" src="./script.js" defer></script>
</head>

<body>
  <header>
    <h1>Data Management</h1>
  </header>
  <main>
    <p><textarea class="data p" id="article"></textarea></p>
  </main>
</body>

</html>
GenericUser
  • 2,828
  • 1
  • 10
  • 17
-1

Problem:

You addEventListener to any input

Solution:

Filter by keycode

this.onkeyup = function(e) {
    if (e.keyCode != 32) {
 // Your code here
}
}

You can use this site to know the for any keyboard input keycode.info


You can find snipt

document.querySelectorAll('textarea').forEach(element => {
  element.style.height = `${element.scrollHeight}px`
  this.onkeyup = function(e) {
    if (e.keyCode != 32) {
      element.addEventListener('input', event => {
        event.target.style.height = `${event.target.scrollHeight}px`
      })
    }
  }

})
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf8" />
  <meta name="viewport" content="width=device-width" , initial-scale="1.0" />
  <title>Data Management</title>
  <link href="style.css" rel="stylesheet" type="text/css">
  <script type="module" src="./script.js" defer></script>
</head>

<body>
  <header>
    <h1>Data Management</h1>
  </header>
  <main>
    <p>
      <textarea class="data p" id="article"></textarea>
    </p>
  </main>
</body>

</html>