Reputation: 13968
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:
Upvotes: 101
Views: 167582
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
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
Reputation: 4953
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
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, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'")
.replace(/ /g, ' ');
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
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>
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
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:
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
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
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
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
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
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
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
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
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
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
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);
}
});
Upvotes: 6
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, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>');
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
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
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