Sumit Ghewade
Sumit Ghewade

Reputation: 483

How to expand textarea upwards and its parent divs along with it

I'm creating a chat application(React). I'm having this textbox which I need to expand vertically upwards as user types. I tried doing it with position absolute but it takes it out of the normal flow. And this does not allow the parent div to move upwards. Is there a way that this can be done? If anyone could point me in the right direction that would be great. Thanks.

Here is the codepen link.

https://codepen.io/ghewadesumit/pen/zYzRjyY

<div class='chat-inputbox-container'>
  <div class='chat-inputbox-wrapper'>
    <div class='chat-microphone-container'>
      <div class='chat-microphone'></div>
    </div>
    <div class='inputbox-container'>
      <div class='inputbox-wrapper'>
        <textarea type='text' class='chat-input-box'></textarea>
        <div class='input-box-btn'></div>
      </div>
      <div class='input-character-container'>
        <span class='input-character'>

          250 out of 250 characters left
        </span>
      </div>
    </div>
  </div>
</div>

css

.chat-inputbox-container {
  /* border: 1px solid red; */
  width: 100%;
  height: 113px;
  align-self: flex-end;
  display: flex;
  justify-content: center;
}

.chat-inputbox-wrapper {
  width: 736px;
  height: 92px;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}

.chat-microphone-container {
  width: 32px;

  height: 92px;
  /* border: 1px solid orange; */
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 10px;
}

.chat-microphone {
  width: 32px;
  height: 32px;

  background: orangered;
}

.inputbox-wrapper {
  width: 694px;
  height: 52px;
  /* border: 1px solid blue; */
  display: flex;
  align-self: flex-end;
  align-items: center;
  margin-top: 16px;

  background: gray;

  border: 1px solid red;
  box-sizing: border-box;
  border-radius: 4px;
}

.chat-input-box {
  width: 632px;
  height: 20px;

  font-size: 14px;
  line-height: 20px;

  border: hidden;
  background: #f7f7f7;
  outline: none;
  color: #0d1c3d;
  margin: 16px 10px;
}

.input-box-btn {
  /* Auto Layout */

  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  padding: 0px;

  position: static;
  width: 32px;
  height: 32px;

  margin-right: 10px;
  background: #0078b3;
  border-radius: 4px;
  flex: none;
  order: 0;
  flex-grow: 0;
  margin: 0px 0px;
}

.input-character-container {
}

.input-character {
  font-size: 12px;
  line-height: 16px;
  color: #677083;
}

Upvotes: 0

Views: 1336

Answers (4)

Yupma
Yupma

Reputation: 2544

Don't hard code the height of class .inputbox-wrapper instead remove height property from there or put height: auto(which is default value) so that container expand when the the text-area is expanded

.chat-inputbox-container {
  /* border: 1px solid red; */
  width: 100%;
  height: 113px;
  align-self: flex-end;
  display: flex;
  justify-content: center;
}

.chat-inputbox-wrapper {
  width: 736px;
  height: 92px;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}

.chat-microphone-container {
  width: 32px;

  height: 92px;
  /* border: 1px solid orange; */
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 10px;
}

.chat-microphone {
  width: 32px;
  height: 32px;

  background: orangered;
}

.inputbox-wrapper {
  width: 694px;
  height: auto;/*Change here*/
  /* border: 1px solid blue; */
  display: flex;
  align-self: flex-end;
  align-items: center;
  margin-top: 16px;

  background: gray;

  border: 1px solid red;
  box-sizing: border-box;
  border-radius: 4px;
}

.chat-input-box {
  width: 632px;
  height: 20px;

  font-size: 14px;
  line-height: 20px;

  border: hidden;
  background: #f7f7f7;
  outline: none;
  color: #0d1c3d;
  margin: 16px 10px;
}

.input-box-btn {
  /* Auto Layout */

  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  padding: 0px;

  position: static;
  width: 32px;
  height: 32px;

  margin-right: 10px;
  background: #0078b3;
  border-radius: 4px;
  flex: none;
  order: 0;
  flex-grow: 0;
  margin: 0px 0px;
}

.input-character-container {
}

.input-character {
  font-size: 12px;
  line-height: 16px;
  color: #677083;
}
<div class='chat-inputbox-container'>
  <div class='chat-inputbox-wrapper'>
    <div class='chat-microphone-container'>
      <div class='chat-microphone'></div>
    </div>
    <div class='inputbox-container'>
      <div class='inputbox-wrapper'>
        <textarea type='text' class='chat-input-box'></textarea>
        <div class='input-box-btn'></div>
      </div>
      <div class='input-character-container'>
        <span class='input-character'>

          250 out of 250 characters left
        </span>
      </div>
    </div>
  </div>
</div>

Upvotes: 2

A Haworth
A Haworth

Reputation: 36626

We can use a Javascript ResizeObserver to tell us when the height of the input text has changed. Then we can scroll the window in such a way that the bottom of the input stays in the same position on the viewport - so the elements seem to grow upwards.

Note this snippet uses contenteditable on a div rather than a textarea as the growing/shrinking and text wrapping then happen automatically.

<style>
  body {
    height: 300vh;
  }
  
  .parent {
    margin-top: 20vh; /* so we can see it growing not just disappearing */
    background: pink;
  }
  
  .child {
    background: #eeeeee;
  }
</style>

<body>
  <div class="parent">
    Some stuff in the parent<br> here
    <div class="child" contenteditable></div>
  </div>
  <script>
    let prevH = 0;
    const textArea = document.querySelector('.child');
    const resizeObserver = new ResizeObserver(entries => {
      for (let entry of entries) {
        let h = entry.contentRect.height;
        let diff = h - prevH;
        if (diff != 0) {
          prevH = h;
          window.scroll(0, prevH);
        }
      }
    });
    resizeObserver.observe(textArea);
  </script>
</body>

Upvotes: 3

dave
dave

Reputation: 2901

Textboxes can't expand their height automatically like this by default - you'll need to use a bit of Javascript.

One approach is to dynamically calculate the height of the textfield based on the number of line breaks inside it.

This example from CSS-Tricks has more details on the approach. I've implemented it on your code below.

You also need to change height to min-height on your inputbox-wrapper to allow it to expand as the textfield changes height.

let textarea = document.querySelector(".chat-input-box");
textarea.addEventListener("keyup", () => {
  textarea.style.height = calcHeight(textarea.value) + "px";
});

function calcHeight(value) {
  let numberOfLineBreaks = (value.match(/\n/g) || []).length;
  // min-height + lines x line-height + padding + border
  let newHeight = 20 + numberOfLineBreaks * 20 + 0 + 0;
  // padding and border are both 0 here but have left in for reference
  return newHeight;
}
.chat-inputbox-container {
  /* border: 1px solid red; */
  width: 100%;
  height: 113px;
  align-self: flex-end;
  display: flex;
  justify-content: center;
}

.chat-inputbox-wrapper {
  width: 736px;
  height: 92px;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}

.chat-microphone-container {
  width: 32px;

  height: 92px;
  /* border: 1px solid orange; */
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 10px;
}

.chat-microphone {
  width: 32px;
  height: 32px;

  background: orangered;
}

.inputbox-wrapper {
  width: 694px;
  min-height: 52px;
  /* border: 1px solid blue; */
  display: flex;
  align-self: flex-end;
  align-items: center;
  margin-top: 16px;

  background: gray;

  border: 1px solid red;
  box-sizing: border-box;
  border-radius: 4px;
}

.chat-input-box {
  width: 632px;
  height: 20px;

  font-size: 14px;
  line-height: 20px;

  border: hidden;
  background: #f7f7f7;
  outline: none;
  color: #0d1c3d;
  margin: 16px 10px;
}

.input-box-btn {
  /* Auto Layout */

  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  padding: 0px;

  position: static;
  width: 32px;
  height: 32px;

  margin-right: 10px;
  background: #0078b3;
  border-radius: 4px;
  flex: none;
  order: 0;
  flex-grow: 0;
  margin: 0px 0px;
}

.input-character-container {
}

.input-character {
  font-size: 12px;
  line-height: 16px;
  color: #677083;
}
<div class='chat-inputbox-container'>
  <div class='chat-inputbox-wrapper'>
    <div class='chat-microphone-container'>
      <div class='chat-microphone'></div>
    </div>
    <div class='inputbox-container'>
      <div class='inputbox-wrapper'>
        <textarea type='text' class='chat-input-box'></textarea>
        <div class='input-box-btn'></div>
      </div>
      <div class='input-character-container'>
        <span class='input-character'>

          250 out of 250 characters left
        </span>
      </div>
    </div>
  </div>
</div>

Upvotes: 1

user16061639
user16061639

Reputation:

The .inputbox-wrapper should have a min-height not a height if you set only a height, the container will not resize with the textbox.

On another note, if you want the textarea to expand vertically only, you can add resize: vertical; to .chat-input-box {

enter image description here

Upvotes: 1

Related Questions