How to create a highly adaptive textarea

I"ve noticed that SF"s comment box is highly adaptive now, which means that no matter how many words you type, you won"t have that pesky scroll bar, which is good. I probably took a look at its technical implementation, as if replacing textarea with a div, and then setting the current div"s contentEditable to true . This implementation is similar to that of quora.

but there is a problem with this implementation, that is, the support for browsers is not very good. Of course, SF clearly does not support IE6. I do not have other versions of IE at hand, so I do not know how the support is. Generally speaking, ie needs to do a lot of hack with contentEditable to remain compatible. Another browser, opera,opera "s contentEditable support for div, has only recently begun.

another implementation is that the answer you will get when you search on the Internet is

$("textarea").keyup(function () {
    $(this).height(this.scrollHeight);
});

basically all jquery plug-ins are based on this code, but it actually has a very lame effect

  1. it responds to keyup events, so there must be delays. The visual representation is that a scroll bar appears first, and then the text box is elongated. The experience is very awkward.
  2. it also has compatibility issues, and on some browsers (such as safari), its scrollHeight is inexplicably more, which looks very strange.

this is my analysis of this feature. All I want is a normal text box that can respond to stretching quickly under most browsers (ie6 can be ignored). If you are using contentEditable , you need to support the following functions

  1. only copy plain text, html will be filtered out
  2. good newline support
  3. support undo and redo

this kind of text box experience is actually very good, if you can discuss a better solution here, it can also benefit many front-end developers.

May.29,2022

Ultimate answer

A few days ago, there was a highly adaptive need for textarea. Find a plug-in flexText ,
although not used, but the simplified code is very attractive to me.

it works like this. The structure of HTML is as follows:

<div class="expandingArea">
    
<span></span><br>
< textarea placeholder= "enter text" > < / textarea > < / div >

the style of expandingArea is only

.expandingArea{
    position:relative;
}

purpose is for absolute positioning of textarea relative to expandingArea:

textarea{
    position:absolute;
    top:0;
    left:0;
    height:100%;
}

with this style setting, the height of textArea is always equal to the height of expandingArea, and you only need to adjust the height of
expadingArea to make the height of textarea change. So how do you make the height of expandingArea change with the height of the content? Pre is an important
thing.

pre{
    display:block;
    visibility:hidden;
}

pre exists in blocks and is invisible, but it takes up space, unlike display:none;, which takes up nothing. At this point, you need to synchronize the content in textarea to the span tag in pre in real time. Because pre does not have postion:absolute , its height will always affect the height of expandingArea. The summary principle is: pre will change with the height of content, and the height of expandingArea will change with pre, because the height of textarea textarea will change with expandingArea . As long as you synchronize the content of textarea to pre, you will achieve the goal of textarea with content height.

the compatibility of this method is mentioned in the blog of the founder of this method NEIL JENKINS . Personally, I think this method is powerful, did not pass the calculation, logically it is like thinking derivation, the code implementation is not complex, relaxed and happy. In this example, we see another case where a reasonable structure can simplify the code:).


it is true that I have tested a lot of solutions when thinking about this feature. In addition to the two solutions you mentioned, I have also used a solution that I am testing, but if I can improve some glitches, the experience will certainly be better than the current one.

I think of it this way. Since scrollHeight cannot be trusted, we need to look for a trusted height standard. We create another div so that its css is completely inherited from this textarea, because the height of div can float and scale freely, so we intercept the keyup event of textarea and send its contents to div, and then we define the height of textarea by getting the height of textarea.

before implementing this function, there is another function that needs to be implemented, that is, copying css to another element. Even if there is already a ready-made jQuery solution on the Internet

// csspatch, $(el).css()
jQuery.fn.css2 = jQuery.fn.css;
jQuery.fn.css = function() {
    if (arguments.length) return jQuery.fn.css2.apply(this, arguments);
    var attr = ['font-family','font-size','font-weight','font-style','color',
        'text-transform','text-decoration','letter-spacing', 'box-shadow',
        'line-height','text-align','vertical-align','direction','background-color',
        'background-image','background-repeat','background-position',
        'background-attachment','opacity','width','height','top','right','bottom',
        'left','margin-top','margin-right','margin-bottom','margin-left',
        'padding-top','padding-right','padding-bottom','padding-left',
        'border-top-width','border-right-width','border-bottom-width',
        'border-left-width','border-top-color','border-right-color',
        'border-bottom-color','border-left-color','border-top-style',
        'border-right-style','border-bottom-style','border-left-style','position',
        'display','visibility','z-index','overflow-x','overflow-y','white-space',
        'clip','float','clear','cursor','list-style-image','list-style-position',
        'list-style-type','marker-offset'];
    var len = attr.length, obj = {};
    for (var i = 0; i < len; iPP) 
        obj[attr[i]] = jQuery.fn.css2.call(this, attr[i]);
    return obj;
};

with these two codes, we can implement

$('textarea').keyup(function () {
    var t = $(this);
    
    if (!this.justifyDoc) {
        this.justifyDoc = $(document.createElement('div'));

        // copy css
        this.justifyDoc.css(t.css()).css({
            'display'   :   'block',        // you can change to none
            'word-wrap' :   'break-word',
            'min-height':   t.height(),
            'height'    :   'auto'
        }).insertAfter(t.css('overflow-y', 'hidden'));
    }

    var html = t.val().replace(/&/g, '&')
        .replace(/</g, '<')
        .replace(/>/g, '>')
        .replace(/'/g, ''')
        .replace(/"/g, '"')
        .replace(/ /g, '')
        .replace(/(()*)/g, '$1 ')
        .replace(/\n/g, '<br />')
        .replace(/<br \/>[ ]*$/, '<br />-')
        .replace(/<br \/> /g, '<br />');

    this.justifyDoc.html(html);
    t.height(this.justifyDoc.height());
});

it runs as follows

it has only one problem, that is, there is a little delay in line wrapping, that is, character wrapping first. Then it will be stretched, because we are responding to the keyup event. Actually, I think the delay is insurmountable, but can you think of a way to make the process less abrupt?


I've been using this code
https://gist.github.com/1192205


it's too complicated to read your answers. My solution: get the number of textarea newline characters, and then update their line height

$('textarea').on('input propertychange', function() {
            var v = $(this).val();
            var arr = v.split('\n');
            var len = arr.length;
            $(this).height(len*20);//20;
        });
        

if you want to keep the set number of lines when the number of lines of content is small, you can do this:

$('textarea').on('input propertychange', function() {
            var v = $(this).val();
            var arr = v.split('\n');
            var len = arr.length;
            var min=$(this)[0].rows;
            if(len>min){
                  $(this).height(len*20);//20;
            }
        });

you can add a hidden textArea (similar to the first floor method), take the scrollHeight of this textArea and set it to the input textArea, but here you still have to deal with some compatibility issues after taking the value. With regard to the keyup event, it is best to replace it with the oninput event and the onpropertychange event, so that you can deal with the problem of adding or deleting text with the mouse, but it seems that deleting text using the backspace key under ie9 will not trigger the onpropertychange event.


means that when you enter, adding a line height should not cause the scroll bar to flicker.

/** fake code **/
textarea.keydown = function(e){
    if e.keycode == 13 { // key code 13
        textarea.height = textarea.height + 1em;
    }
}

try

/** fake code **/
textarea.keydown = function(e){
    if e.keycode == 13 { // key code 13
        textarea.height = textarea.height + 1em;
    }
}

http://www.jacklmoore.com/autosize/
This plugin can perfectly solve the problems you have encountered


my idea is to use a div to get the content of the textarea in real time, because the div height varies according to the content. We can get the height of div, and then set the height of div to textarea.

< hr class= answer > h
hh
h
h
hh
h
hh
h


not below, you ask me ~

<textarea class="form-control" style="padding: 0; margin: 0;box-sizing: content-box;" oninput="this.style.height = this.scrollHeight+'px'">  ~~~</textarea>

jq implements textarea highly adaptive . If you don't want to escape the scroll bar, you can overflow and hide


, but the height will not shrink back

when deleted.
Menu