CSS Textarea that expands as you type text

I have a Textarea where users can input text. By default it has a height of 17px. However if users insert a large amount of text, I want the text area to expand accordingly. Is there a way to do this with CSS ? Thanks in advance!!

Answers:

Answer

This cannot be done with CSS alone. try the autogrow jquery plugin. https://github.com/jaz303/jquery-grab-bag/blob/master/javascripts/jquery.autogrow-textarea.js

You can also see autogrow demo here http://onehackoranother.com/projects/jquery/jquery-grab-bag/autogrow-textarea.html

It's lightweight and easy to use. Here's how it's done. Define your textarea id. Include the jquery js file before </body>. Then between script tags, issue the jquery command $("#txtInput").autoGrow();

<body>
    <textarea id="txtInput"></textarea>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script> 

<script>
    $("#txtInput").autogrow();
</script>
</body>
Answer

This jQuery plugin is a really great one: http://www.jacklmoore.com/autosize

I've tested a bunch of these and this is by far the nicest. Also gives an example of using a CSS transition effect which is pretty slick.

Answer

**Note this is very similar to Woody's answer above but wanted to expand upon it a little and provide a running code example now that Stack allows us to embed them.

After reading through all of this and trying a couple of plugins, I found that none of this quite worked as I had hoped. I did the following - there is a slight jitter at the top of the field as you scroll before it expands, but it works for me. I used jquery, but can be done with javascript just as easily by grabbing the padding values instead of using inner height:

  • Set a minimum height on the textarea in CSS
  • Set overflow to hidden for vertical scrolling (I just wanted to expand vertically)
  • Set the height to the scroll height less padding on each keyup event if scroll height was higher than height + padding (innerHeight).
  • If scroll height was not taller, I re-set the height to 1, and then set the height to the scroll height less padding (to shrink the height). If you don't reset to a smaller height initially the scroll height won't shrink.

$(function() {
  $('#myTextArea').on('keyup paste', function() {
    var $el = $(this),
        offset = $el.innerHeight() - $el.height();

    if ($el.innerHeight() < this.scrollHeight) {
      // Grow the field if scroll height is smaller
      $el.height(this.scrollHeight - offset);
    } else {
      // Shrink the field and then re-set it to the scroll height in case it needs to shrink
      $el.height(1);
      $el.height(this.scrollHeight - offset);
    }
  });
});
#myTextArea {
  width: 250px;
  min-height: 35px;
  overflow-y: hidden;
}
<script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
<textarea id="myTextArea" placeholder="Hit enter a few times, it should expand"></textarea>

Answer

I know this is a little bit late, but I have to say there is a way to use <div> with contenteditable attribute to simulate desired behaviour.

.textareaElement {
  width: 300px;
  min-height: 17px;
  border: 1px solid #ccc;
  max-height: 150px;
  overflow-x: hidden;
  overflow-y: auto;
}
<div class="textareaElement" contenteditable></div>

Just set your min and max height, with proper overflow values, and you have fully functional pure CSS expanding textbox, that is also well supported.

enter image description here

Answer

You don't need a plugin for this. This works on textareas of any size, height or row size and will only work when the contents exceeds the textarea. Firstly set the overflow on your target textareas to hidden and resize to none, then add the following functionality to the textareas you want to autogrow. Not only will it increase the textarea's size as the user types, it'll also auto-shrink it when they delete stuff.

$('textarea').on('paste input', function () {
    if ($(this).outerHeight() > this.scrollHeight){
        $(this).height(1)
    }
    while ($(this).outerHeight() < this.scrollHeight + parseFloat($(this).css("borderTopWidth")) + parseFloat($(this).css("borderBottomWidth"))){
        $(this).height($(this).height() + 1)
    }
});

It works by measuring if the scroll height of the textarea is bigger than the outer height, which it only will be if there's more text than the textarea can hold - and it takes border size into account for higher accuracy. Using paste and input means it will only increase when the user physically changes the value of the textarea, as opposed to when they press any key. It's petty but a textarea shouldn't grow when somebody presses an arrow key or something.

It might be prudent to add a No JS option that re-enables overflow and resizing for those who don't have Javascript, else they'll be stuck with a tiny box.

Answer

Use JavaScript for this.

This script checks the lenth of text area after every keystroke there (copypasta from here):

  <textarea name="x" onKeyUp="SetNewSize(this);" cols="5" rows="4"></textarea>
    <script language="javascript">
    function SetNewSize(textarea){
      if (textarea.value.length > 5){
        textarea.cols = 50;
        textarea.rows = 50;
      }  else{
         textarea.cols = 10;
         textarea.rows = 15;
      }
    }
  </script>
Answer

A little bit late, but this worked for me like a charm, it's in jquery:

This textarea have a limit height of 200px, and a starting height of 22px. The padding helps a lot to keep the text in a good place, but, we have to play with weights depending on the size of the font.

There is a similar answer in another question, but this one is a little bit more complete.

$('textarea').each(function () {
  // Do something if you want
}).on('input', function () {
  this.style.height = 'auto';
  // Customize if you want
  this.style.height = (this.scrollHeight - 30) + 'px'; //The weight is 30
});
textarea{
    padding: 7px;
    width: 50%;
    height: 22px;
    max-height: 200px;
    resize: none;
    overflow-y: scroll;
    font-size: 16px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>Textarea:</div>
<textarea></textarea>

Answer

Expanding textarea as you type

Type something in textarea to see the effect

<script>    
function increseRows(selector)
{
    $(selector).attr("rows", $(selector).val().split("\n").length+1||2);
}
</script>

expanding textarea as you type

Answer

I use the following (with jQuery of course):

$(function () {
    'use strict';
    $("textarea").on('change keyup paste input', function () {
        $(this).attr("rows", Math.max($(this).val().split("\n").length || 1, $(this).attr("rows") || 1));
        $(this).css("width", $(this).css("width"));
    }).trigger('change');
});

Note that it responds to various events, only increases the number of lines (i.e. doesn't decrease), triggers an initial change (e.g. to resize when browsing back to a form with lots of lines)

Answer

This seems to be much more efficient and handles max-height

$(ctrl).on('paste input', function () {
    var dyLineHeight, dyMax, dyHeight;        
    if ($(this).outerHeight() > this.scrollHeight)
        $(this).height($(this).outerHeight() - parseFloat($(this).css("borderBottomWidth")) - parseFloat($(this).css("borderTopWidth")));
    dyLineHeight = Math.max(3, parseInt($(this).css("line-height")));
    dyMax = parseInt($(this).css("max-height"));
    while ($(this).outerHeight() < this.scrollHeight + parseFloat($(this).css("borderTopWidth")) + parseFloat($(this).css("borderBottomWidth")))
        {
        dyHeight = $(this).height();
        if (dyHeight >= dyMax)
            break;
        $(this).height(dyHeight + dyLineHeight)
        }
});
Answer

I was looking for pure js solution (no jquery in projects) and end-up writing own solution. It is very fast, no compatibility issues and requires no extra libs.

One detail to take care about is that you need to size up box before new character appears, but size down the box after character disappears (after hitting backspace or delete)

function updateSize(e) {
  let text = e.target.value + String.fromCharCode(event.keyCode);
  e.target.rows = text.split(/\r\n|\r|\n/).length;
}

function keyDownUpdateSize(e) {
  if (event.keyCode != 8 && event.keyCode != 46)
    updateSize(e);
}

function keyUpUpdateSize(e) {
  if (event.keyCode == 8 || event.keyCode == 46)
    updateSize(e);
}

    
  
document.querySelector(selector_to_your_textarea).addEventListener("keydown", keyDownUpdateSize);
document.querySelector(selector_to_your_textarea).addEventListener("keyup", keyUpUpdateSize);

Answer

Old question but you could do something like this:

html:

<textarea class="text-area" rows="1"></textarea>

jquery:

var baseH; // base scroll height

$('body')
    .one('focus.textarea', '.text-area', function(e) {
        baseH = this.scrollHeight;
    })
    .on('input.textarea', '.text-area', function(e) {
        if(baseH < this.scrollHeight) {
            $(this).height(0).height(this.scrollHeight);
        }
        else {
            $(this).height(0).height(baseH);
        }
    });

This way the auto resize will apply to any textarea with the class "text-area". Also shrinks when text is removed.

jsfiddle:

https://jsfiddle.net/rotaercz/46rhcqyn/

Answer

Use Javascript. textarea behaves like a textarea, and you want to change that (you want it to behave like a div), so you have to hack in the behavior you want.

Here's a solution I found somewhere a few months ago but have not been able to find again. It may have my own flavor added in:

Markup:

<div>
  <textarea class='my-textarea' />
  <div className='my-textarea autogrow' style="display: 'none';" />
</div>

Styles:

.my-textarea {
  border: 1px solid #bbb;
  font-family: Helvetica;
  font-size: 15px;
  overflow: hidden;
  padding: 5px;
  resize: none;
}

// Needs same styles as the textarea except overflow.
.autogrow {
  overflow: auto !important;
}

Get this event listener onto the textarea's change event:

function growTextarea(e) {
  const { value } = e.target
  const textarea = e.target
  const { grower } = this

  grower.style.display = 'block'
  grower.innerHTML = value.length ? value : 'x'
  textarea.style.height = grower.offsetHeight + 'px'
  grower.style.display = 'none'
}

How does it work? Basically a div's expansion is what you want the textarea's expansion to behave like. So you're making a div with all the same styles as the textarea and putting the textarea's value into the div. Then you get the div's height and set the textarea's height to that.

Using display none and block, the div appears and disappears so you can measure its height. You'll never actually see it in the browser.

Hope this works for you!

P.S. I use React so I had to change my solution to be framework agnostic. So it may have bugs or syntax errors. E.g. you might have to query the document to find the grower div.

Answer

If you are using Angular2/4 there is a great directive here that works.

See the issues list for when you are loading data dynamically into the textarea for a workaround. Other than that issue it works fine with ReactiveForms and Template forms.

For reference, this is the directive code:

import { Input, AfterViewInit, ElementRef, HostListener, Directive} from '@angular/core';

@Directive({
    selector: 'textarea[autosize]'
})

export class Autosize implements AfterViewInit {

    private el: HTMLElement;
    private _minHeight: string;
    private _maxHeight: string;
    private _lastHeight: number;
    private _clientWidth: number;

    @Input('minHeight')
    get minHeight() { 
      return this._minHeight;
    }
    set minHeight(val: string) {
      this._minHeight = val;
      this.updateMinHeight();
    }

    @Input('maxHeight')
    get maxHeight() {
      return this._maxHeight; 
    }
    set maxHeight(val: string) {
      this._maxHeight = val;
      this.updateMaxHeight();
    }

 @HostListener('window:resize', ['$event.target'])
    onResize(textArea: HTMLTextAreaElement) {
      //Only apply adjustment if element width had changed.
      if (this.el.clientWidth === this._clientWidth) return;
      this._clientWidth = this.element.nativeElement.clientWidth;
      this.adjust();
    }

 @HostListener('input',['$event.target'])
  onInput(textArea: HTMLTextAreaElement): void {
    this.adjust();  
  }

  constructor(public element: ElementRef){
    this.el = element.nativeElement;
    this._clientWidth = this.el.clientWidth;
  }

  ngAfterViewInit(): void{
    // set element resize allowed manually by user
    const style = window.getComputedStyle(this.el, null);
    if (style.resize === 'both') {
            this.el.style.resize = 'horizontal';
        }
    else if (style.resize === 'vertical') {
            this.el.style.resize = 'none';
    }
    // run first adjust
    this.adjust();
  }

  adjust(): void{
    // perform height adjustments after input changes, if height is different
    if (this.el.style.height == this.element.nativeElement.scrollHeight + "px") return;
    this.el.style.overflowX = 'hidden';
    this.el.style.height = 'auto';
    this.el.style.height = this.el.scrollHeight + "px";
  }

  updateMinHeight(): void{
    // Set textarea min height if input defined
    this.el.style.minHeight = this._minHeight + 'px';
  }

  updateMaxHeight(): void{
    // Set textarea max height if input defined
    this.el.style.maxHeight = this._maxHeight + 'px';
  }

}
Answer
function autoExpand(field) {

    // Reset field height
    field.style.height = 'inherit';

    // Get the computed styles for the element
    var computed = window.getComputedStyle(field);

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

    field.style.height = height + 'px';

};

Works for me

https://gomakethings.com/automatically-expand-a-textarea-as-the-user-types-using-vanilla-javascript/

Answer

var textarea = document.querySelector('textarea');
textarea.addEventListener('keydown', autosize);             
function autosize(){
  var el = this;
  setTimeout(function(){
    el.style.cssText = 'height:auto; padding:0';    
    el.style.cssText = 'height:' + el.scrollHeight + 'px';
  },0);
}
textarea{   
  overflow:hidden; 
  padding:10px;
  width:250px;
  font-size:14px;
  margin:50px auto;
  display:block;
  border-radius:10px;
  border:6px solid #556677;
}
<textarea rows="6" >
CSS Textarea that expands as you type text
rows Specifies the visible number of lines in a text area and cols	Specifies the visible width of a text area
</textarea>

Answer

came up with simple solution for React Angular or Vue.

You just need to wrap the textarea in a div, write the content of textarea in the div and give the textarea absolute position, height and width 100% (don't forget relative position on the div).

So now the div and the textarea are perfectly superimposed, and when the div is expanding because of the text inside, textarea will automatically do so.

Don't forget to set exact same padding, font-size and font-family.

Answer

this worked for me

$(".textarea").on("keyup input", function(){
    $(this).css('height', 'auto').css('height', this.scrollHeight+(this.offsetHeight - 
    this.clientHeight));
 });

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.