How to make text area to fit dynamic content completely without any overflow?

Viewed 3681

This is an angular app (but anyone with css knowledge can help), where there is a text area with dynamic content.

So as the content item.text changes the text area should grow or shrink according to the content to fit the content perfectly without any overflow.

<textarea [value]="item.text" [placeholder]="item.text ? '' : 'Your Text Here...'" class="font-xl font-bold"></textarea>

// dont worry about the placeholder. you can ignore that.

Currently in my case scrollbar appears & it is not shrinking or growing with the dynamic content.

How can I achieve that?

Or if there is a way to convert a regular html <div> to a textarea, you can suggest that too. But prefers a solution for the above one.

I've tried css rules like, max-content fit-content etc... nothing is working out!

5 Answers

Install npm install ngx-autosize

in html add autosize

<textarea autosize [value]="item.text" [placeholder]="item.text ? '' : 'Your Text Here...'" class="font-xl font-bold"></textarea>

then in appmodule

put in imports: [AutosizeModule ],

Demo

This can't be accomplished with just css, it needs JavaScript that has quite a few corner cases and can be tricky. Such as, pasted input, input populated programatically, auto filled input, handling screen size changes correctly, and on and on, and doing so in a way that is reusable and performs well.

Given all that, I recommend using a lib for this.

I've used angular material's plenty of times with no issues, just add material to your project (can be done via angular CLI with ng add @angular/material) and either import the MatInputModule from @angular/material/input or TextFieldModule from @angular/cdk/text-field (TextFieldModule is quite a bit smaller) to the module where you want to use it, then do:

<textarea cdkTextareaAutoSize cdkAutosizeMinRows="5" [value]="item.text" [placeholder]="item.text ? '' : 'Your Text Here...'" class="font-xl font-bold"></textarea>

you can exclude the cdkAutosizeMinRows option and then it will default to 1 row, but you can use that option to set however many minimum rows you'd like to display. You can also use the cdkAutosizeMaxRows option to make it stop growing at a certain number of rows if you wish, otherwise it will grow indefinitely with the content.

blitz: https://stackblitz.com/edit/angular-4zlkw1?file=src%2Fapp%2Ftext-field-autosize-textarea-example.html

docs: https://material.angular.io/components/input/overview#auto-resizing-textarea-elements

https://material.angular.io/cdk/text-field/overview

You can't change the height of the textarea without Javascript. But you can use an editable div instead. In plain HTML something like this would serve the same purpose as an textarea and will resize automatically based on the content.

<div class="font-xl font-bold" contentEditable>Hello World</div>

If you use a <div> which you can edit then it can grow or shrink accordingly.

<div contenteditable="true">This is a div. It is editable. Try to change this text.</p>

The below will loop over the item and compare height to scrollHeight incrementing the height by lineHeight. Then resets the rows once the height is greater than the scroll height

(function () {
  const el = document.querySelector('textarea');
  dynamicallyResize(el);
  el.addEventListener('change', function () { dynamicallyResize(el); });
})();

function dynamicallyResize(el) {
  el == undefined && (el = this.target);
  const lineHeight = 16;
  let i = el.getAttribute('rows'), 
      height = Math.ceil(el.getBoundingClientRect().height);
  el.style.overflow = 'visible'; //triger redraw
  while(height < el.scrollHeight) { 
      height += lineHeight;
      i++; 
      el.setAttribute('rows', i); 
  }
  el.style.overflow = 'auto';
}
<textarea [value]="item.text" [placeholder]="item.text ? '' : 'Your Text Here...'" class="font-xl font-bold" rows="2">Starting text that exceeds the 2 row limit initially placed on this particular text area.</textarea>

Related