Automatically scale input [type = text] to a width value?
Is there a way to scale the width of <input type="text"> to the width of the actual value?
You can do this in a simple way by setting the size attribute to the length of the input content:
function resizeInput() { $(this).attr('size', $(this).val().length); } $('input[type="text"]') // event handler .keyup(resizeInput) // resize on page load .each(resizeInput); See: http://jsfiddle.net/nrabinowitz/NvynC/
It seems that adding some add-ons on the right, which I suspect is browser dependent. If you want it to be very dense for input, you can use a technique like the one I describe in this related answer , using jQuery to calculate the pixel size of your text.
If for some reason other solutions do not work for you, you can use contenteditable-span instead of the input element.
<span contenteditable="true">dummy text</span> Note that this is more of a hack and has a serious flaw that allows for completely non-anonymous HTML input, allowing users to enter (and insert) lines, links and other HTML.
So, you probably shouldn't use this solution unless you sanitize the entrance very carefully ...
Update : you probably want to use the Obsidian solution below .
SIMPLICITY BUT PIXEL PERFECT SOLUTION
I saw several ways to do this, but calculating the width of the fonts is not always 100% accurate, it's just an estimate.
I managed to create the perfect pixel way to adjust the input width using a hidden replacement object.
jQuery (recommended)
$(function() { . $( '# ') ($ ( '# TXT') ().); . $( '# TXT') ($ ( '# ') ().); }). on ('input', function() { . $( '# ') ($ ( '# TXT') ().); . $( '# TXT') ($ ( '# ') ().); });> body, #, #{ : ; : 0; : 0; } #{ : ; : # 888; -: 10px; } #{ : ; -: ; }> < script src= "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery. min.js" > < &/; GT <p> Lorem ipsum < span id = "hide" > </span> < input id = "txt" type = "text" value = "type here..." > egestas arcu. </ >> Pure javascript
I was not able to determine how jQuery calculates the width of the hidden elements, so posting this solution requires a small change in css.
var hide = document.getElementById('hide'); var txt = document.getElementById('txt'); (); txt.addEventListener( "enter", ); function resize() { hide.textContent = txt.value; txt.style.width = hide.offsetWidth + "px"; }> body, #, # { font: inherit; margin: 0; : 0; } # { border: none; : # 888; -: 10 ; } # { : ; : 0; : ; white-space: pre; }> <p> Lorem ipsum < span id = "hide" > </span> < input id = "txt" type = "text" value = "type here..." > egestas arcu. </ >> Change Now the plugin works with trailing whitespace. Thanks for pointing out @JavaSpyder
Since most of the other answers didn't match what I needed (or just didn't work at all) I changed Adrian B's answer to the correct jQuery plugin, which leads to perfect input scaling in pixels without the need to change your css or html.
Example: https://jsfiddle.net/587aapc2/
Usage: $("input").autoresize({padding: 20, minWidth: 20, maxWidth: 300});
Plugin:
//JQuery plugin: $.fn.textWidth = function(_text, _font){//get width of text with font. usage: $("div").textWidth(); var fakeEl = $('<span>').hide().appendTo(document.body).text(_text || this.val() || this.text()).css({font: _font || this.css('font'), whiteSpace: "pre"}), width = fakeEl.width(); fakeEl.remove(); return width; }; $.fn.autoresize = function(options){//resizes elements based on content size. usage: $('input').autoresize({padding:10,minWidth:0,maxWidth:100}); options = $.extend({padding:10,minWidth:0,maxWidth:10000}, options||{}); $(this).on('input', function() { $(this).css('width', Math.min(options.maxWidth,Math.max(options.minWidth,$(this).textWidth() + options.padding))); }).trigger('input'); return this; } //have <input> resize automatically $("input").autoresize({padding:20,minWidth:40,maxWidth:300}); <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <input value="i magically resize"> <br/><br/> called with: $("input").autoresize({padding: 20, minWidth: 40, maxWidth: 300}); I have a jQuery plugin on GitHub: https://github.com/MartinF/jQuery.Autosize.Input
It reflects the input value, calculates the width, and uses it to set the input width.
Here you can see a live example: http://jsfiddle.net/mJMpw/2175/
An example of how to use it (since some code is needed when sending the jsfiddle link):
<input type="text" value="" placeholder="Autosize" data-autosize-input='{ "space": 40 }' /> input[type="data-autosize-input"] { width: 90px; min-width: 90px; max-width: 300px; transition: width 0.25s; } You just use css to set min / max-width and use the width transition if you want a nice effect.
You can specify a space / distance to the end as a value in json notation for the input-autosize-input attribute on the input element.
Of course you can just initialize it with jQuery
$("selector").autosizeInput(); There are already many good answers. For fun, I implemented this solution below, based on other answers and my own ideas.
<input class="adjust"> The input element is fine-tuned and an additional offset can be determined.
function adjust(elements, offset, min, max) { // Initialize parameters offset = offset || 0; min = min || 0; max = max || Infinity; elements.each(function() { var element = $(this); // Add element to measure pixel length of text var id = btoa(Math.floor(Math.random() * Math.pow(2, 64))); var tag = $('<span id="' + id + '">' + element.val() + '</span>').css({ 'display': 'none', 'font-family': element.css('font-family'), 'font-size': element.css('font-size'), }).appendTo('body'); // Adjust element width on keydown function update() { // Give browser time to add current letter setTimeout(function() { // Prevent whitespace from being collapsed tag.html(element.val().replace(/ /g, ' ')); // Clamp length and prevent text from scrolling var size = Math.max(min, Math.min(max, tag.width() + offset)); if (size < max) element.scrollLeft(0); // Apply width to element element.width(size); }, 0); }; update(); element.keydown(update); }); } // Apply to our element adjust($('.adjust'), 10, 100, 500); Customization is smoothed using a CSS transition.
.adjust { transition: width .15s; } Here is the fiddle . Hope this helps others looking for a clean solution.
You can solve this problem like here :) http://jsfiddle.net/MqM76/217/
HTML:
<input id="inpt" type="text" /> <div id="inpt-width"></div> JS:
$.fn.textWidth = function(text, font) { if (!$.fn.textWidth.fakeEl) $.fn.textWidth.fakeEl = $('<span>').hide().appendTo(document.body); $.fn.textWidth.fakeEl.text(text || this.val() || this.text()).css('font', font || this.css('font')); return $.fn.textWidth.fakeEl.width(); }; $('#inpt').on('input', function() { var padding = 10; //Works as a minimum width var valWidth = ($(this).textWidth() + padding) + 'px'; $('#'+this.id+'-width').html(valWidth); $('#inpt').css('width', valWidth); }).trigger('input'); Unfortunately, the size attribute will not work very well. Sometimes there will be extra space and too little space, depending on the font settings. (see example)
If you want this to work well, try looking at the input changes and then resize it. You probably want to set it to scrollWidth input. We will also need to consider the size of the window.
In the following example, I set the input size to 1 so that it does not have scrollWidth that is larger than our initial width (set manually using CSS).
// (no-jquery document.ready) function onReady(f) { "complete" === document.readyState ? f() : setTimeout(onReady, 10, f); } onReady(function() { [].forEach.call( document.querySelectorAll("input[type='text'].autoresize"), registerInput ); }); function registerInput(el) { el.size = 1; var style = el.currentStyle || window.getComputedStyle(el), borderBox = style.boxSizing === "border-box", boxSizing = borderBox ? parseInt(style.borderRightWidth, 10) + parseInt(style.borderLeftWidth, 10) : 0; if ("onpropertychange" in el) { // IE el.onpropertychange = adjust; } else if ("oninput" in el) { el.oninput = adjust; } adjust(); function adjust() { // reset to smaller size (for if text deleted) el.style.width = ""; // getting the scrollWidth should trigger a reflow // and give you what the width would be in px if // original style, less any box-sizing var newWidth = el.scrollWidth + boxSizing; // so let set this to the new width! el.style.width = newWidth + "px"; } } * { font-family: sans-serif; } input.autoresize { width: 125px; min-width: 125px; max-width: 400px; } input[type='text'] { box-sizing: border-box; padding: 4px 8px; border-radius: 4px; border: 1px solid #ccc; margin-bottom: 10px; } <label> Resizes: <input class="autoresize" placeholder="this will resize" type='text'> </label> <br/> <label> Doesn't resize: <input placeholder="this will not" type='text'> </label> <br/> <label> Has extra space to right: <input value="123456789" size="9" type="text"/> </label> I think this should work even in IE6, but don't take my word for it.
Depending on your use case, you may need to bind the configuration function to other events. For example. by changing the input value programmatically or by changing the display style property from none (where scrollWidth === 0 ) to block or inline-block , etc.
Instead of trying to create a div and measure its width, I think it is more reliable to measure the width directly with the canvas element, which is more accurate.
function measureTextWidth(txt, font) { var element = document.createElement('canvas'); var context = element.getContext("2d"); context.font = font; return context.measureText(txt).width; } Now you can use this to measure how wide an input element should be at any given time by doing this:
// assuming inputElement is a reference to an input element (DOM, not jQuery) var style = window.getComputedStyle(inputElement, null); var text = inputElement.value || inputElement.placeholder; var width = measureTextWidth(text, style.font); This returns a number (possibly a floating point). If you want to consider registration, you can try the following:
var desiredWidth = (parseInt(style.borderLeftWidth) + parseInt(style.paddingLeft) + Math.ceil(width) + 1 + // extra space for cursor parseInt(style.paddingRight) + parseInt(style.borderRightWidth)) inputElement.style.width = desiredWidth + "px"; My jQuery plugin works for me:
Using:
$('form input[type="text"]').autoFit({ }); jquery.auto-fit.js Source jquery.auto-fit.js :
; (function ($) { var methods = { init: function (options) { var settings = $.extend(true, {}, $.fn.autoFit.defaults, options); var $this = $(this); $this.keydown(methods.fit); methods.fit.call(this, null); return $this; }, fit: function (event) { var $this = $(this); var val = $this.val().replace(' ', '-'); var fontSize = $this.css('font-size'); var padding = $this.outerWidth() - $this.width(); var contentWidth = $('<span style="font-size: ' + fontSize + '; padding: 0 ' + padding / 2 + 'px; display: inline-block; position: absolute; visibility: hidden;">' + val + '</span>').insertAfter($this).outerWidth(); $this.width((contentWidth + padding) + 'px'); return $this; } }; $.fn.autoFit = function (options) { if (typeof options == 'string' && methods[options] && typeof methods[options] === 'function') { return methods[options].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof options === 'object' || !options) { // Default to 'init' return this.each(function (i, element) { methods.init.apply(this, [options]); }); } else { $.error('Method ' + options + ' does not exist on jquery.auto-fit.'); return null; } }; $.fn.autoFit.defaults = {}; })(this['jQuery']); Input elements behave differently than other elements that will do what you need if you give them float: left (see http://jsfiddle.net/hEvYj/5/ ). I don't think this is possible without calculating it in any way using JavaScript (i.e. add 5px to the width of the letter in the box).
The user solution nrabinowitz works fine, but I use the keypress event instead of keyup . This reduces latency if the user slowly enters data.
Here is my modification of the nrabinowitz solution. I did not use the size property because it is not perfect with proportional fonts, as @Mark noted. My solution puts the element after input and gets the width calculated by the browser (using jQuery).
Although I am not testing it, I believe that it will work only if all CSS properties affecting the font are inherited.
The width of the input signal changes to a focusout event, which works better for me. But you can use keyup / keypress to change the input width as you type.
function resizeInput() { //Firstly take the content or placeholder if content is missing. var content = $(this).val().length > 0 ? $(this).val() : $(this).prop("placeholder"); //Create testing element with same content as input. var widthTester = $("<span>"+content+"</span>").hide(); //Place testing element into DOM after input (so it inherits same formatting as input does). widthTester.insertAfter($(this)); //Set inputs width; you may want to use outerWidth() or innerWidth() //depending whether you want to count padding and border or not. $(this).css("width",widthTester.width()+"px"); //Remove the element from the DOM widthTester.remove(); } $('.resizing-input').focusout(resizeInput).each(resizeInput); Using the canvas, we can calculate the width of the elements:
function getTextWidth(text, fontSize, fontName) { let canvas = document.createElement('canvas'); let context = canvas.getContext('2d'); context.font = fontSize + fontName; return context.measureText(text).width; } and use it for the selected event:
function onChange(e) { let width = getTextWidth(this.value, $(this).css('font-size'), $(this).css('font-family')); $(this.input).css('width', width); } try canvas measureText solution
CSS
input{ min-width:10px!important; max-width:99.99%!important; transition: width 0.1s; border-width:1px; } JavaScript:
function getWidthOfInput(input){ var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var text = input.value.length ? input.value : input.placeholder; var style = window.getComputedStyle(input); ctx.lineWidth = 1; ctx.font = style.font; var text_width = ctx.measureText(text).width; return text_width; } function resizable (el, factor) { function resize() { var width = getWidthOfInput(el); el.style.width = width + 'px'; } var e = 'keyup,keypress,focus,blur,change'.split(','); for (var i in e){ el.addEventListener(e[i],resize,false); } resize(); } $( "input" ).each( function(i){ resizable(this); });