180

I am filling a textarea with content for the user to edit.

Is it possible to make it stretch to fit content with CSS (like overflow:show for a div)?

Cave Johnson
  • 6,499
  • 5
  • 38
  • 57
significance
  • 4,797
  • 8
  • 38
  • 57
  • 5
    Doesn't anyone have an answer that doesn't have any bugs that doesn't use a framework? :-( – starbeamrainbowlabs Nov 23 '16 at 07:29
  • I simply use the css max-width:100% and it automatically fits a box. Any problem with that? – yashas123 Aug 12 '18 at 15:39
  • 1
    Here's a modern solution (uses one line of JS and some CSS wizardry): [codepen](https://codepen.io/shshaw/pen/c72208b279d750f1ab46b6a45bbd04d7). – Oliver Dec 27 '20 at 11:59
  • @yashas123 the problem with that is that it does not handle, e.g., a textarea which has input longer than the height of the browser window (neither does max-height: 100%, etc) – Taylor D. Edmiston May 22 '23 at 17:47

14 Answers14

391

one line only

<textarea name="text" oninput='this.style.height = "";this.style.height = this.scrollHeight + "px"'></textarea>
j08691
  • 204,283
  • 31
  • 260
  • 272
Martin Prestone
  • 4,223
  • 2
  • 9
  • 8
  • 11
    how does this have only two votes. this is incredible Martin. I just spend 30 minutes trying to solve this. Great work. – Philip Duffney Mar 10 '18 at 23:38
  • 57
    This is great. I'd just like to add that changing `this.scrollHeight + "px"` to `this.scrollHeight + 3 + "px"` makes the textarea big enough to have it not show the scrollbar. – maarten Mar 31 '18 at 13:01
  • 6
    Problem: When the user writes enough to scroll down, it resets the scroll position every time they add a new line with Enter. – Costa Michailidis Oct 26 '18 at 18:11
  • 1
    This works for what I need, but isn't actually an answer to the question, which asked for CSS solution. – Autumn Leonard Feb 07 '19 at 16:34
  • 10
    I know this is an old question, but I have a textarea on an edit page, and it has a value already when the page loads, how can I make it expand to fit content then? – Arootin Aghazaryan Mar 04 '19 at 02:37
  • 3
    @ArootinAghazaryan - You might already have figured a solution out, but for anyone else: Just create a function with the resize code instead of having it inline in the HTML. Then you can call the same function on page load. – M. Eriksson Apr 28 '19 at 13:04
  • I use `event.target.style.height = event.target.scrollHeight + 8 + 'px'`, then trigger this from controls' onChange event, which passes in the control in question to resize. (The 8 removes scrollbars - thanks @maarten - 3 wasn't enough for macOS Chrome.) Accepted answer so complicated I assume it is brittle (on no evidence). – Chris Jun 07 '19 at 09:49
  • it can be hard to catch a page loading, specially if you use vue etc. so this is a simple solution, update on mousemove, and its looks great) onmousemove='this.style.height = "";this.style.height = this.scrollHeight + "px"' – Martin Prestone Nov 28 '19 at 10:23
  • When content is just a single line of text - textarea is about two lines in size for some reason. – Sam Tyurenkov Mar 27 '20 at 23:31
  • @MartinPrestone If you're using Vue, you have access to the `mounted` hook. Use that. – Joe C. Oct 28 '20 at 19:02
  • What if you have an initial value such as a saved value, prior to user input? – Emperor Eto Mar 03 '21 at 14:52
  • 5
    Adding `style="overflow: hidden;"` can make scrollbar invisible, instead of manually plus some small px to height. – thetaprime Mar 24 '21 at 06:32
  • i needed to google for this and this is the solution fitting best for my needs. ty – Paulquappe Jul 13 '21 at 08:03
  • 1
    @SamTyurenkov That's because the default value of the "rows" attribute is 2. Set rows="1" on the textarea if you want to have the textarea start with an initial height of 1 row – Robin-Hoodie Jul 27 '21 at 06:50
  • @MartinPrestone, onmousemove still requires the user to mouse over the input. I used onfocus='this.style.height = "";this.style.height = this.scrollHeight + "px"' with autofocus='true' - does the job! To be precise, this was for Sweetalert2: inputAttributes: {'autofocus': true, 'onfocus': 'this.style.height = "";this.style.height = this.scrollHeight + 3 + "px"'}, – Ken Nov 08 '21 at 20:31
  • Great answer. However, for those who have applied top and bottom padding to the textarea then you need to subtract it from the scrollheight. – Pawan Singh Jan 28 '22 at 13:05
  • This only works once you start typing something into it, but not when you first display the textarea – JBoy Mar 23 '23 at 15:58
53

Not really. This is normally done using javascript.

there is a good discussion of ways of doing this here...

Autosizing textarea using Prototype

Community
  • 1
  • 1
Rik Heywood
  • 13,816
  • 9
  • 61
  • 81
19

Alternatively, you could use a contenteditable element, this will fit to the text inside.

<div contenteditable>Try typing and returning.</div>

Please note that it's not possible to send this value along in a form, without using some javascript. Also contenteditable will possibly generate HTML-content and allows styling, so this may need to be filtered out upon form submit.

Tim
  • 2,805
  • 25
  • 21
  • 2
    This is the best solution for me – amir22 Jan 09 '22 at 10:18
  • 1
    This is a great alternative to an usual – Yann Masoch Jan 25 '23 at 17:58
  • There are accessibility concerns with this approach. – Zach Saucier Apr 26 '23 at 20:24
  • best solution. remember, if you want your content to appear as is, put it inside a ```pre``` tag and don't forget to set css overflow to scroll. ```
    Try typing and returning.
    ```
    – Udo E. Jul 09 '23 at 02:42
9

Not 100% related to the question as this is for Angular when using Angular Material Design only.

There is a npm package associated with Angular called @angular/cdk (if using Angular Material Design). There is a property included in this package that can be associated to a textarea called cdkTextareaAutosize. This automatically sets the textarea to 1 line and stretches the textarea to fit the content accordingly. If you are using this library, something like this should work.

<textarea 
  maxLength="200"
  cdkTextareaAutosize
  type="text">
</textarea>
Martyn93
  • 338
  • 4
  • 9
8

Here is a function that works with jQuery (for height only, not width):

function setHeight(jq_in){
    jq_in.each(function(index, elem){
        // This line will work with pure Javascript (taken from NicB's answer):
        elem.style.height = elem.scrollHeight+'px'; 
    });
}
setHeight($('<put selector here>'));

Note: The op asked for a solution that does not use Javascript, however this should be helpful to many people who come across this question.

Chris Dutrow
  • 48,402
  • 65
  • 188
  • 258
7

This is a very simple solution, but it works for me:

<!--TEXT-AREA-->
<textarea id="textBox1" name="content" TextMode="MultiLine" onkeyup="setHeight('textBox1');" onkeydown="setHeight('textBox1');">Hello World</textarea>

<!--JAVASCRIPT-->
<script type="text/javascript">
function setHeight(fieldId){
    document.getElementById(fieldId).style.height = document.getElementById(fieldId).scrollHeight+'px';
}
setHeight('textBox1');
</script>
NicB
  • 342
  • 2
  • 3
  • 6
    The height of the box increases with *every* key stroke, not just new lines. Even backspace and delete cause the height to increase. Fix, and you'll get the upvote back. – Birrel Mar 12 '16 at 20:58
  • some browsers like IE don't calculate scrollheight quite correctly, which can cause those kinds of issues. never mind that's happening for me in Chrome as well... – KthProg Apr 24 '17 at 15:45
  • 1
    here's the solution (edit queue is full): ` ` basically you have to set the height to 1px first, due to this: http://stackoverflow.com/questions/10722058/height-of-textarea-increases-when-value-increased-but-does-not-reduce-when-value – KthProg Apr 24 '17 at 15:55
5

Answers here were good but were lacking a piece of code that I had to add to avoid a shrinking that is not welcome when you type for the first time :

var $textareas = $('textarea');
$textareas.each(function() { // to avoid the shrinking
    this.style.minHeight = this.offsetHeight + 'px';
});

$textareas.on('input', function() {
    this.style.height = '';
    this.style.height = this.scrollHeight + 'px';
});
FTW
  • 922
  • 1
  • 7
  • 19
4

Another simple solution for dynamic textarea control.

<!--JAVASCRIPT-->
<script type="text/javascript">
$('textarea').on('input', function () {
            this.style.height = "";
            this.style.height = this.scrollHeight + "px";
 });
</script>
Krutika Patel
  • 420
  • 5
  • 16
2

There are a lot of answers here already, but I think some improvement can still be made to the textarea resizing code.

This script snippet will loop over ALL of the textareas on your page, and make sure they resize both on load and on change.

<script>
  document.querySelectorAll("textarea").forEach(element => {
    function autoResize(el) {
      el.style.height = el.scrollHeight + 'px';
    }
    autoResize(element);
    element.addEventListener('input', () => autoResize(element));
  });
</script>

Vanilla JS only, no libraries needed.

dezman
  • 18,087
  • 10
  • 53
  • 91
  • When I implement this solution, the textbox resizes on every keystroke. If I type, "Hi Mom,", the textarea expands by 7 lines, one line at a time for each character typed. – Bobby Jun 27 '23 at 20:15
  • I added a regular comment below which incorporates dezman's function which works beautifully and FTW's solution from just above this one which I didn't understand well enough to make it work. FTW used the .offsetHeight property to make setting styleHeight conditional; I didn't know there was such a thing! Thank you FTW. Anyway, this seems to have cured the shrinking textarea problem. THANK YOU BOTH. – Bobby Jun 27 '23 at 22:34
0

A reliable, reusable, more complete answer that is responsive (watches for window resizes). You can place the code in a JavaScript module, refer to comments below on how it works:

// File: ui.mjs

/* Auto resize a <textarea>'s height to fit its content.
 * Use the HTML attribute `rows` to set the min height of the element, e.g. rows="2"
 */
function runAutoHeight(el) {
    el.style.height = 'auto';
    const computedStyle = getComputedStyle(el)
    const borderTop = parseFloat(computedStyle.getPropertyValue("border-top-width").replace('px',''));
    const borderBottom = parseFloat(computedStyle.getPropertyValue("border-bottom-width").replace('px',''));
    el.style.height = String(el.scrollHeight + borderTop + borderBottom) + 'px';
}

/* Sets up autoHeight for the given element for the following 2 situations:
 *  1. When the user types in input
 *  2. When the element is resized (e.g. window is resized)
 *
 * It also adds a function to the element called 'autoHeight', which can be manually called.
 * This is useful when setting values to a <textarea> via JS, and hence the `input` event
 * handler will not be run, e.g.:
 *      import * as ui from '/static/path/to/your/ui.mjs';
 *      ui.setupAutoHeight(el)
 *      el.value = "Manually setting value won't fire change event"
 *      el.autoHeight()
 */
export function setupAutoHeight(el) {
    el.autoHeight = () => runAutoHeight(el);
    el.style.resize = "none";
    // Watch for window resizes
    const observer = new ResizeObserver(el.autoHeight);
    observer.observe(el);
    // Watch for changes in text input
    el.addEventListener('input', el.autoHeight)
}
run_the_race
  • 1,344
  • 2
  • 36
  • 62
0

If you are using ionic just add this attribute to the text area:

 autoGrow="true" 

See this answer: ion-textarea resize height dynamically in Ionic 5

Anas
  • 711
  • 7
  • 24
0
    <script>
        document.querySelectorAll("textarea").forEach(element => {
            function autoResize(el) {
                if (el.scrollHeight > el.offsetHeight) {
                    el.style.height = el.scrollHeight + 'px';
                }
            }
            autoResize(element);
            element.addEventListener('input', () => autoResize(element));
        });
    </script>

Solution for the shrinking when typing input I experienced in dezman's fantastic function (see dezman above). I added a comparison to the property which FTW referenced in his post just above dezman's named .offsetHeight.

In dezman's function, when the scrollHeight is less than the offsetHeight—–e.g. 1 line of text in a 5 line size textarea––then the adjustment made to el.style.height after each keystroke was inadvertently reducing the size of the offsetheight. The offset kept shrinking toward the scrollHeight which gave the appearance of a shrinking textarea.

Firing the adjustment to style.height only when text entry causes an increase in the scrollHeight past the .offsetheight prevents the offsetHeight from shrinking with every keystroke.

THANK YOU dezman and FTW above...

Bobby
  • 137
  • 11
0

Not quite a <textarea> but you can always use:

<div contenteditable="true"></div>

which, in some contexts, works as an excellent drop-in replacement for <textarea>.


Working Example:

.textbox {
  width: 400px;
  padding: 12px;
  box-sizing: border-box;
  outline: 1px solid red;
}
<div class="textbox" contenteditable="true">
This div is editable like a textarea. It expands when more words are typed into the available area... keep typing and you'll see how the more you type, the more it grows...
</div>

Further Reading:

Rounin
  • 27,134
  • 9
  • 83
  • 108
-2

Solution for React

I used the length of the text that was being displayed and divided that number by 30 (I adjusted this number until it felt right form my App)

{array.map((text) => (
    <textarea                
     rows={text.length / 30}
     value={text}
    ></textarea>
 )}
  • 2
    Why not use `rows={text.split("\n").length}`? This will set the number of rows to be the number of rows in the content. This will not cover text longer than the width resulting in a word-wrap however. – Glenn O Nov 09 '22 at 09:53