Stann
Stann

Reputation: 13968

make html text input field grow as I type?

I can set initial text input size in css, like so:

width: 50px;

But I would like it to grow when I type until it reaches for example 200px. Can this be done in straight css, html, preferably without javascript?

Do post your js/jquery solutions too of course, but if this is doable without them - that be great.

my try here:

http://jsfiddle.net/jszjz/2/

Upvotes: 101

Views: 167582

Answers (19)

pery mimon
pery mimon

Reputation: 8343

In the near future you could use :
field-sizing: content;

As you can read about here

The field-sizing CSS property enables you to control the sizing behavior of elements ... This property enables you to override the default sizing behavior, allowing form controls to adjust in size to fit their contents.

This property is typically used to style text <input> and <textarea> elements to allow them to shrinkwrap their content as well as grow when more text is entered into the form control.

And watch about it here

Upvotes: -1

Fenish Sakariya
Fenish Sakariya

Reputation: 1

.editable {
  display: inline-block;
  min-width: 50px;
  max-width: 200px;
  border: 1px solid #ccc;
  padding: 5px;
  white-space: nowrap;
  overflow: hidden;
}
<div class="editable" contenteditable="true"></div>

Upvotes: 0

For those looking for a solution in 2024, this is now supported natively on CSS. Use the new field-sizing: content on the input/textarea element.

input, textarea {
  field-sizing: content;
}

Be aware that this is still not supported by all browser vendors. See compatibility here

Upvotes: 0

Paul
Paul

Reputation: 141907

I just wrote this for you, I hope you like it :) No guarantees that it's cross-browser, but I think it is :)

(function() {

  var min = 100,
    max = 300,
    pad_right = 5,
    input = document.getElementById('adjinput');

  input.style.width = min + 'px';
  input.onkeypress = input.onkeydown = input.onkeyup = function() {
    var input = this;
    setTimeout(function() {
      var tmp = document.createElement('div');
      tmp.style.padding = '0';
      if (getComputedStyle)
        tmp.style.cssText = getComputedStyle(input, null).cssText;
      if (input.currentStyle)
        tmp.style = input.currentStyle;
      tmp.style.width = '';
      tmp.style.position = 'absolute';
      tmp.innerHTML = input.value.replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#039;")
        .replace(/ /g, '&nbsp;');
      input.parentNode.appendChild(tmp);
      var width = tmp.clientWidth + pad_right + 1;
      tmp.parentNode.removeChild(tmp);
      if (min <= width && width <= max)
        input.style.width = width + 'px';
    }, 1);
  }

})();
#adjinput {
  width: 100px;
}
<input type = 'text' value='' id='adjinput' />

Upvotes: 65

Joe
Joe

Reputation: 82654

Here is an example with only CSS and Content Editable:

span {
  border: solid 1px black;
}

div {
  max-width: 200px;
}
<div>
  <span contenteditable="true">sdfsd</span>
</div>


Important note regarding contenteditable

Making an HTML element contenteditable lets users paste copied HTML elements inside of this element. This may not be ideal for your use case, so keep that in mind when choosing to use it.

Upvotes: 117

Michael Dimmitt
Michael Dimmitt

Reputation: 1064

https://css-tricks.com/auto-growing-inputs-textareas had an interesting solution that requires no library: https://codepen.io/shshaw/pen/bGNJJBE

Simplified here: https://codepen.io/michaeldimmitt/pen/mdGXgjy In order to be simplified:

  • Content editable needed two spaces to start out
  • This allows the parent element to compensate with the input having a natural padding.

Note: adding size="20" to specify starting out width would be 20 characters long.


/* css */
.input-sizer {
  display: inline-grid;

  &::after {
    content: attr(data-value) '  ';
    visibility: hidden;
    white-space: pre-wrap;
  }
}

/* html */
<label class="input-sizer">
  <input  type="text" size="1"
    onInput="this.parentNode.dataset.value = this.value"
    placeholder="5"
  >
</label>

Upvotes: 1

jameshfisher
jameshfisher

Reputation: 36579

You can do this with display: inline-grid:

const dummy = document.querySelector(".dummy");
const input = document.querySelector("input");

const update = () => dummy.innerText = input.value;
input.oninput = update;
update();
.growing-input {
  display: inline-grid;
}

.growing-input .dummy,
.growing-input input {
  grid-area: 1 / 1;
  
  /* Following properties just need to be consistent,
  to ensure the .dummy and the input take up the same space */
  font: inherit;
  padding: 0 0.25em;
  margin: 0;
  border: 1px solid grey;
  border-radius: 2px;
}

.growing-input .dummy {
  visibility: hidden;
  white-space: pre-wrap;
}
Here's an 
<span class="growing-input">
  <input type="text" value="auto-resizing input" size="1" />
  <span class="dummy"></span>
</span>; have fun!

The idea is to create a dummy element containing the same content as the input, then set the input width to match that of the dummy element. Above we use JavaScript to synchronize the text, and a display: inline-grid trick to set the input width to match.

(This approach is taken from this article; I've condensed it to the bare essentials.)

Upvotes: 3

Anthony Rosario
Anthony Rosario

Reputation: 1

All you need to do is, get the element of the input field you want to grow as you type and in CSS, set the width of the input to auto and set a min-width to say 50px.

Upvotes: -2

Chen W
Chen W

Reputation: 319

For those strictly looking for a solution that works for input or textarea, this is the simplest solution I've came across. Only a few lines of CSS and one line of JS.

The JavaScript sets a data-* attribute on the element equal to the value of the input. The input is set within a CSS grid, where that grid is a pseudo-element that uses that data-* attribute as its content. That content is what stretches the grid to the appropriate size based on the input value.

Upvotes: 0

jscul
jscul

Reputation: 772

If you're allowed to use the ch measurement (monospaced) it completely solved what I was trying to do.

onChange(e => {
    e.target.style.width = `${e.target.length}ch`;
})

This was exactly what I needed but I'm not sure if it works for dynamic width font-families.

Upvotes: 1

Aaron Mason
Aaron Mason

Reputation: 362

Here's a method that worked for me. When you type into the field, it puts that text into the hidden span, then gets its new width and applies it to the input field. It grows and shrinks with your input, with a safeguard against the input virtually disappearing when you erase all input. Tested in Chrome. (EDIT: works in Safari, Firefox and Edge at the time of this edit)

function travel_keyup(e)
{
    if (e.target.value.length == 0) return;
    var oSpan=document.querySelector('#menu-enter-travel span');
    oSpan.textContent=e.target.value;
    match_span(e.target, oSpan);
}
function travel_keydown(e)
{
    if (e.key.length == 1)
    {
        if (e.target.maxLength == e.target.value.length) return;
        var oSpan=document.querySelector('#menu-enter-travel span');
        oSpan.textContent=e.target.value + '' + e.key;
        match_span(e.target, oSpan);
    }
}
function match_span(oInput, oSpan)
{
    oInput.style.width=oSpan.getBoundingClientRect().width + 'px';
}

window.addEventListener('load', function()
{
    var oInput=document.querySelector('#menu-enter-travel input');
    oInput.addEventListener('keyup', travel_keyup);
    oInput.addEventListener('keydown', travel_keydown);

    match_span(oInput, document.querySelector('#menu-enter-travel span'));
});
#menu-enter-travel input
{
	width: 8px;
}
#menu-enter-travel span
{
	visibility: hidden;
    position: absolute;
    top: 0px;
    left: 0px;
}
<div id="menu-enter-travel">
<input type="text" pattern="^[0-9]{1,4}$" maxlength="4">KM
<span>9</span>
</div>

Upvotes: 0

lastmjs
lastmjs

Reputation: 1014

If you set the span to display: inline-block, automatic horizontal and vertical resizing works very well:

<span contenteditable="true" 
      style="display: inline-block;
             border: solid 1px black;
             min-width: 50px; 
             max-width: 200px">
</span>

Upvotes: 13

user6912175
user6912175

Reputation:

Which approach you use, of course, depends on what your end goal is. If you want to submit the results with a form then using native form elements means you don't have to use scripting to submit. Also, if scripting is turned off then the fallback still works without the fancy grow-shrink effects. If you want to get the plain text out of a contenteditable element you can always also use scripting like node.textContent to strip out the html that the browsers insert in the user input.

This version uses native form elements with slight refinements on some of the previous posts.

It allows the content to shrink as well.

Use this in combination with CSS for better control.

<html>

<textarea></textarea>
<br>
<input type="text">


<style>

textarea {
  width: 300px;
  min-height: 100px;
}

input {
  min-width: 300px;
}


<script>

document.querySelectorAll('input[type="text"]').forEach(function(node) {
  var minWidth = parseInt(getComputedStyle(node).minWidth) || node.clientWidth;
  node.style.overflowX = 'auto'; // 'hidden'
  node.onchange = node.oninput = function() {
    node.style.width = minWidth + 'px';
    node.style.width = node.scrollWidth + 'px';
  };
});

You can use something similar with <textarea> elements

document.querySelectorAll('textarea').forEach(function(node) {
  var minHeight = parseInt(getComputedStyle(node).minHeight) || node.clientHeight;
  node.style.overflowY = 'auto'; // 'hidden'
  node.onchange = node.oninput = function() {
    node.style.height = minHeight + 'px';
    node.style.height = node.scrollHeight + 'px';
  };
});

This doesn't flicker on Chrome, results may vary on other browsers, so test.

Upvotes: 2

ceving
ceving

Reputation: 23871

If you are just interested in growing, you can update the width to scrollWidth, whenever the content of the input element changes.

document.querySelectorAll('input[type="text"]').forEach(function(node) {
  node.onchange = node.oninput = function() {
    node.style.width = node.scrollWidth+'px';
  };
});

But this will not shrink the element.

Upvotes: 3

b0rgBart3
b0rgBart3

Reputation: 304

I know this is a seriously old post - but my answer might be useful to others anyway, so here goes. I found that if my CSS style definition for the contenteditable div has a min-height of 200 instead of a height of 200 , then the div scales automatically.

Upvotes: 2

muffs
muffs

Reputation: 805

How about programmatically modifying the size attribute on the input?

Semantically (imo), this solution is better than the accepted solution because it still uses input fields for user input but it does introduce a little bit of jQuery. Soundcloud does something similar to this for their tagging.

<input size="1" />

$('input').on('keydown', function(evt) {
    var $this = $(this),
        size = parseInt($this.attr('size'), 10),
        isValidKey = (evt.which >= 65 && evt.which <= 90) || // a-zA-Z
                     (evt.which >= 48 && evt.which <= 57) || // 0-9
                     evt.which === 32;

    if ( evt.which === 8 && size > 0 ) {
        // backspace
        $this.attr('size', size - 1);
    } else if ( isValidKey ) {
        // all other keystrokes
        $this.attr('size', size + 1);
    }
});

http://jsfiddle.net/Vu9ZT/

Upvotes: 6

cmpolis
cmpolis

Reputation: 3051

From: Is there a jQuery autogrow plugin for text fields?


See a demo here: http://jsbin.com/ahaxe

The plugin:

(function($){

    $.fn.autoGrowInput = function(o) {

        o = $.extend({
            maxWidth: 1000,
            minWidth: 0,
            comfortZone: 70
        }, o);

        this.filter('input:text').each(function(){

            var minWidth = o.minWidth || $(this).width(),
                val = '',
                input = $(this),
                testSubject = $('<tester/>').css({
                    position: 'absolute',
                    top: -9999,
                    left: -9999,
                    width: 'auto',
                    fontSize: input.css('fontSize'),
                    fontFamily: input.css('fontFamily'),
                    fontWeight: input.css('fontWeight'),
                    letterSpacing: input.css('letterSpacing'),
                    whiteSpace: 'nowrap'
                }),
                check = function() {

                    if (val === (val = input.val())) {return;}

                    // Enter new content into testSubject
                    var escaped = val.replace(/&/g, '&amp;').replace(/\s/g,'&nbsp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
                    testSubject.html(escaped);

                    // Calculate new width + whether to change
                    var testerWidth = testSubject.width(),
                        newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
                        currentWidth = input.width(),
                        isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
                                             || (newWidth > minWidth && newWidth < o.maxWidth);

                    // Animate width
                    if (isValidWidthChange) {
                        input.width(newWidth);
                    }

                };

            testSubject.insertAfter(input);

            $(this).bind('keyup keydown blur update', check);

        });

        return this;

    };

})(jQuery);

Upvotes: 3

Pantelis
Pantelis

Reputation: 6146

Here you can try something like this

EDIT: REVISED EXAMPLE (added one new solution) http://jsfiddle.net/jszjz/10/

Code explanation

var jqThis = $('#adjinput'), //object of the input field in jQuery
    fontSize = parseInt( jqThis.css('font-size') ) / 2, //its font-size
    //its min Width (the box won't become smaller than this
    minWidth= parseInt( jqThis.css('min-width') ), 
    //its maxWidth (the box won't become bigger than this)
    maxWidth= parseInt( jqThis.css('max-width') );

jqThis.bind('keydown', function(e){ //on key down
   var newVal = (this.value.length * fontSize); //compute the new width

   if( newVal  > minWidth && newVal <= maxWidth ) //check to see if it is within Min and Max
       this.style.width = newVal + 'px'; //update the value.
});

and the css is pretty straightforward too

#adjinput{
    max-width:200px !important;
    width:40px;
    min-width:40px;
    font-size:11px;
}

EDIT: Another solution is to havethe user type what he wants and on blur (focus out), grab the string (in the same font size) place it in a div - count the div's width - and then with a nice animate with a cool easing effect update the input fields width. The only drawback is that the input field will remain "small" while the user types. Or you can add a timeout : ) you can check such a kind of solution on the fiddle above too!

Upvotes: 2

Seth
Seth

Reputation: 46463

A couple of things come to mind:

Use an onkeydown handler in your text field, measure the text*, and increase the text box size accordingly.

Attach a :focus css class to your text box with a larger width. Then your box will be larger when focused. That's not exactly what you're asking for, but similar.

* It's not straightforward to measure text in javascript. Check out this question for some ideas.

Upvotes: 3

Related Questions