I created a directive in order to make a input that has width automatically resized when keyup (like Google Contacts). However it seems not to be ok, because the width of each characters is different. Could you please help me to give a more optimized way? Tks.
5 Answers
Based on @notme's answer I created the following gist for my own version of an auto-resizing input angular directive:
https://gist.github.com/Zmaster/6923413
Here is the code:
Template:
<span>
<input type="text" ng-model="value">
<span style="visibility:hidden; position:absolute; left:-1000; top:-1000;">{{value}}</span>
</span>
Directive:
angular.module('autoSizeInput', [])
.directive('autoSizeInput', function() {
return {
replace: true,
scope: {
value: '=inputValue'
},
templateUrl: 'templates/directives/autoSizeInput.html',
link: function(scope, element, attrs) {
var elInput = element.find('input');
var elSpan = element.find('span');
elSpan.html(elInput.val());
scope.$watch('value', function(value) {
if(value) {
elSpan.html(elInput.val());
elInput.css('width', (elSpan[0].offsetWidth + 10) + 'px');
}
});
}
};
});

- 1,587
- 1
- 12
- 13
-
1This is excellent. A lot more flexible than [pasine's answer](http://stackoverflow.com/a/17412316/399105) in that it will resize any time the text is changed, not just on keyup, but also more concise than other answers. – bmaupin Dec 03 '14 at 15:25
You can create a dummy span to store the same string you have in your input textfield.
On keyup you refresh the span content and get the new length.
It is better you create a css rule with text style definition for both span and input text, so you are sure they have the same font style.
Your directive would look like this:
.html
<div edit-inline>
<input type="text" value="hello world">
<span class="dummy">blbla</span>
</div>
.js
app.directive("editInline", function(){
return function(scope, element, attr){
var elInput = element.find('input');
var elDummy = element.find('span');
var inputText = elInput.val();
elDummy.html(inputText);
elInput.bind("keyup", function(){
var inputText = elInput.val();
elDummy.html(inputText);
elInput.css('width', elDummy[0].offsetWidth + 'px');
});
}
});
.css
input, .dummy {
font-size: 12px;
font-family: Arial;
white-space:pre;
}
.dummy {
visibility:hidden; // this would prevent the dummy text to be shown without losing its size
}
Here you can see the plunker

- 11,311
- 10
- 49
- 81
-
I see this way is not ok. For example, u have to creat 1 more span, it does not work with space at the ending or when keyuping. – Hieu Tran Jul 02 '13 at 06:53
-
1Adding a white-space:pre; should solve the problem. I have updated the Plunker – pasine Jul 02 '13 at 09:46
-
When typing, the text section is pushed to the left. Can u fix this error? Thank you, @notme – Hieu Tran Jul 02 '13 at 17:05
-
1The problem is that you are binding the resize on keyup, so if hold down a key, the string get larger but the event is not fired. If you can tollerate a whitespace of 10px on the right, you can solve the issue binding both keyup and keydown. I have updated the Plunker. I don't think you could do this without the empty space. You need to have the string written entirely in the textfield in order to update the dummy span, and you need the span to be updated in order to update the textfield width. There are some milliseconds in which the string is larger than the textfield. – pasine Jul 02 '13 at 17:59
-
If you can't tollerate the whitespace, the code has to be re-written in other way. You should prevent the string to be updated on keydown, update the string in the dummy span with the pressed key, update the textfield width and then update the value into the textfield. But I'm not sure it is worth doing a workaround like this just to prevent adding a 10px padding. – pasine Jul 02 '13 at 18:10
-
So the problem is that you have to measure the text in the input. You can't just guess if you want it to fit right.
So this one is more complicated than it might sound, but I think I've got a Plunk here for you that will do the trick.
The basic process:
- Create a temporary span.
- Apply the same font styling to the span.
- Put the value in the span as text.
- Measure the span.
- Delete the span.
Code: and Plunk
app.directive("editInline", function($window){
return function(scope, element, attr){
// a method to update the width of an input
// based on it's value.
var updateWidth = function () {
// create a dummy span, we'll use this to measure text.
var tester = angular.element('<span>'),
// get the computed style of the input
elemStyle = $window.document.defaultView
.getComputedStyle(element[0], '');
// apply any styling that affects the font to the tester span.
tester.css({
'font-family': elemStyle.fontFamily,
'line-height': elemStyle.lineHeight,
'font-size': elemStyle.fontSize,
'font-weight': elemStyle.fontWeight
});
// update the text of the tester span
tester.text(element.val());
// put the tester next to the input temporarily.
element.parent().append(tester);
// measure!
var r = tester[0].getBoundingClientRect();
var w = r.width;
// apply the new width!
element.css('width', w + 'px');
// remove the tester.
tester.remove();
};
// initalize the input
updateWidth();
// do it on keydown so it updates "real time"
element.bind("keydown", function(){
// set an immediate timeout, so the value in
// the input has updated by the time this executes.
$window.setTimeout(updateWidth, 0);
});
}
});
EDIT: also, I've changed it to update the input size asynchronously after a keydown event. This will cause it to update more fluidly when you do things like hold a key down.
-
Note that css duplication is missing `font-style`, which affects width when using italics. **Suggestion:** replace font-family/font-size/font-weight/font-style with a single `'font': elemStyle.font`. (p.s. Thanks @blesh for the solution) – Daryn May 17 '14 at 00:01
-
My above suggestion comment is not valid. It worked in Chrome (v34) but doesn't in FF (v29). So I would just add `'font-style': elemStyle.fontStyle` – Daryn May 20 '14 at 17:21
-
One additional thing that can be added if you have problems with width is `'text-transform': elemStyle.textTransform`. – B-Scan Apr 01 '15 at 10:50
I've done this before. The solution I used is having an off-screen SPAN with the same text in it, with the same exact font as your textbox, and interrogating its width.
I might have something like this:
<span class="textbox-copy"></span>
.textbox-copy {
position: absolute;
left: -9999px;
top: -9999px;
font: -webkit-small-control;
font: -moz-field;
font-size: 13px;
}
Then on keydown set the innerHTML
of that SPAN, and check its current width. Note that, in Chrome and Firefox at least, an unstyled textbox has a special font of its own. It doesn't just inherit Arial or whatever.

- 27,382
- 3
- 35
- 45
I know it's an old discussion but I wanted to share my solution which I believe is better than all given answers. I've just completed writing an angular directive: angular-autogrow:
- No jQuery dependency.
- Simple and high-performance (no $watchers / expensive DOM manipulation).
- Works well with any CSS definition (paddings / box-sizing).

- 1
- 1