CSS Textarea that expands as you type text [duplicate]
Asked Answered
H

18

45

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!!

Honora answered 10/2, 2011 at 6:57 Comment(2)
Hasn't anyone come up with a jquery-free solution to this problem? :-(Oarlock
There is a simple javascirpt solution. 7 lines with alpinejs. https://mcmap.net/q/373974/-how-to-autogrow-a-textarea-with-cssFryer
H
27

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>
Horan answered 10/2, 2011 at 8:16 Comment(2)
Why does the javascriptly link take me bet365.com!!Flew
$('#textInput').autoGrow(); should be $(#txtInput).autogrow();Rosina
O
34

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

Osculum answered 24/3, 2017 at 17:11 Comment(3)
Great solution as I only care about Chrome support. Thanks!Tseng
This is a great solution! The only complication is that when you press enter/return it places all of the new text into a <div> block. So the innerHTML becomes a text node followed by a bunch of <div>s.Phosphorous
I thought this was a great solution too, but if you are doing any manipulation of the text, contentEditable can quickly become a disaster as it does things very differently and the documentation is not great. If you just want a simple text input then, yes, but just be aware there are a lot of curve-balls w/ editableContent.Cyrus
H
27

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>
Horan answered 10/2, 2011 at 8:16 Comment(2)
Why does the javascriptly link take me bet365.com!!Flew
$('#textInput').autoGrow(); should be $(#txtInput).autogrow();Rosina
A
26

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.

Approximal answered 1/11, 2012 at 13:20 Comment(1)
I agree this is the best solution out there. Most importantly, it fixed this bug: When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space made available by removing the scrollbar. The autogrow jquery plugin marked as answer does not have this fix.Witted
S
21

**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 using 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('input 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>
Stithy answered 30/4, 2016 at 17:37 Comment(3)
This works great for me with 'keyup paste input' - except in the case where I'm loading the data from a database. The textarea will expand when I click in it, but as initially displayed it will only show the first line. My JQuery is 'as-needed' so essentially non-existent. I've tried to add a few events e.g. 'ready', 'load' and a couple more but nothing seems to work. Anyone got any tips?Mortimer
There is probably a more elegant way to do this, but you can always fire the keyup event manually so the above code runs after you load your data from the database -- $('#test').keyup(); If it's a static page that is rendered server side with the database data in it, you can put the keyup event in the jquery ready function so it runs after jquery and other libraries are loaded -- $(function() { $('#test').keyup(); });Stithy
Many thanks for the reply. I have tried the keyup without success - maybe because I have many instances of the textbox inside a ListView, and I identify them in the JS by class. I used $(".ExpandableText").keyup(); and also tried with single quotes. No-one's complained about the initial size yet. Only a matter of time though.Mortimer
S
15

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.

Shout answered 7/6, 2015 at 14:39 Comment(4)
It doesn't decrease after.Ballyrag
It works just fine as long as you don't forget to include the jQuery library !!! Yarin jsfiddle is presented without it. But once you choose jQuery 1.9.1 in options, it's all good after.Croatia
@Croatia i did not get that result.Baelbeer
It works, but for some reason on my complex pages with many tables and textareas it is very slow, sometimes it pauses for a second or two after hitting the Enter key.Hetaera
V
3

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>
Vieva answered 10/2, 2011 at 7:4 Comment(0)
L
3

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>
Londalondon answered 4/5, 2019 at 18:4 Comment(1)
Yes! The code is relying in the scrollHeight basically. If you look the css, you 'll find "overflow-y: scroll", everytime the textarea overflows, text will go down, the scrollHeight will increase by the height of the text... So what it does is add the extra height of the scroll to the height of the textarea... To put it simple, the height of the text inside is added to the height of the textarea.Londalondon
C
1

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

Coquetry answered 7/4, 2014 at 7:20 Comment(2)
what is the meaning of ||Makeup
@Manish, it's just the logical "OR" operator, but in this context, it's being used to default to 2 rows if the calculated length somehow evaluates to false.Tallie
B
1

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)

Berlinda answered 3/6, 2015 at 15:59 Comment(3)
This doesn't work. It gives NaN as the rows on any of the four bound events. If there's no newline or there's no "row" attribute already on the textarea, you're trying to do maths with 'undefined'. So, this only works when there's actually new lines to work with... Which is never, because the moment you do anything in the field the bound events are setting the rows to NaN, preventing any further modification.Shout
You're right, the textarea must have a "rows" attribute for my original code to work. I've added a guard (` || 1`) to cater for that.Berlinda
if you change Math.max to Math.round, the textarea will also shrink if you delete text.Orthochromatic
M
1

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)
        }
});
Mettah answered 12/2, 2017 at 17:9 Comment(0)
A
1

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);
Arbe answered 26/4, 2017 at 6:45 Comment(0)
P
1

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/

Preconize answered 10/11, 2017 at 23:22 Comment(0)
E
0

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.

Exception answered 21/5, 2017 at 18:13 Comment(0)
B
0

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';
  }

}
Bilski answered 12/10, 2017 at 19:21 Comment(0)
A
0
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/

Alberta answered 18/3, 2019 at 11:14 Comment(0)
P
0

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>
Pleo answered 18/3, 2019 at 11:29 Comment(4)
Please provide some explanations with your code as well.Hawsepiece
Default text area 6 line that is 6 row. When you / user can type text inside text area automatically text area height is increasing. When you press key autosize() function triggeredPleo
If you add extra jquery plugin others then waste of your time,application loading time taken maybe highPleo
Just try working fine for me. You try and modify based on your requirements.this very simple methodPleo
K
0

this worked for me

$(".textarea").on("keyup input", function(){
    $(this).css('height', 'auto').css('height', this.scrollHeight+(this.offsetHeight - 
    this.clientHeight));
 });
Kazak answered 25/5, 2020 at 16:22 Comment(0)
B
-1

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.

Born answered 9/4, 2019 at 16:30 Comment(1)
It's a lot hackier I would sayDunsinane

© 2022 - 2024 — McMap. All rights reserved.