Reputation: 644
I feel like this should be easy. I've been searching around / trying things out for at least a week, and still to no avail.
I'd like an <input>
element with placeholder text. I'd like the element to only be as wide as the placeholder text. When you click into the <input>
, I'd like the width to remain the same. As you type, if your input text exceeds the width of the original placeholder text (and therefore the <input>
element itself), I'd like the <input>
to expand to accommodate the text.
Thoughts, SO?
Upvotes: 1
Views: 245
Reputation: 51876
I added some minor improvements to @Rounin's answer to make my own attempt:
to  
. In addition, I mapped <
to <
to escape HTML. The reason I did not use textContent
instead of innerHTML
was because there's no way to inject non-breaking spaces into textContent
.width
are actually floats, not integers, so using parseFloat
instead of parseInt
makes the <input/>
width more precise./* Set up */
var regExp = /[ <]/g;
function replacer(c) {
return {
' ': ' ',
'<': '<'
}[c];
}
/* Grab various elements */
var body = document.querySelector('body');
var input = document.querySelector('input');
var placeholder = input.getAttribute('placeholder');
/* Create hiddenSpan */
var hiddenSpan = document.createElement('span');
hiddenSpan.innerHTML = placeholder.replace(regExp, replacer);
/* Style hiddenSpan */
var inputStyles = getComputedStyle(input);
['font', 'padding', 'border', 'display'].forEach(function(prop) {
hiddenSpan.style[prop] = inputStyles.getPropertyValue(prop);
});
hiddenSpan.style.visibility = 'hidden';
hiddenSpan.style.pointerEvents = 'none';
var hiddenSpanStyles = getComputedStyle(hiddenSpan);
/* Initialise <input> width */
body.appendChild(hiddenSpan);
var startWidth = parseFloat(hiddenSpanStyles.getPropertyValue('width'));
body.removeChild(hiddenSpan);
function reviewWidth() {
var inputValue = input.value;
/* Update text content of hiddenSpan */
hiddenSpan.innerHTML = inputValue.replace(regExp, replacer);
body.appendChild(hiddenSpan);
/* Update <input> width */
var newWidth = parseFloat(hiddenSpanStyles.getPropertyValue('width'));
body.removeChild(hiddenSpan);
if (newWidth > startWidth) {
input.style.width = newWidth + 'px';
} else {
input.style.width = startWidth + 'px';
}
}
reviewWidth();
/* Add Event Listener to <input> to trigger reviewWidth() function */
input.addEventListener('input', reviewWidth, false);
input {
font-family: arial, sans-serif;
font-size: 0.8em;
padding: 2px;
}
<input type="text" placeholder="Example Placeholder" />
Feel free to leave comments if you have questions or suggestions to improve this answer.
Upvotes: 0
Reputation: 29463
Here is one attempt (in vanilla javascript
) at a working solution which takes into account different font sizes, different character widths etc.:
function reviewWidth(startWidth) {
/* Grab various elements */
var hiddenSpan = document.getElementsByClassName('hidden')[0];
var inputValue = document.getElementsByTagName('input')[0].value;
/* Update text content of hiddenSpan */
hiddenSpan.innerHTML = inputValue;
/* Update <input> width */
var hiddenSpanStyles = getComputedStyle(hiddenSpan);
var newWidth = parseInt(hiddenSpanStyles.getPropertyValue('width'));
if (newWidth > startWidth) {
input.style.width = newWidth + 'px';
}
else {
input.style.width = startWidth + 'px';
}
}
/* Grab various elements */
var body = document.getElementsByTagName('body')[0];
var input = document.getElementsByTagName('input')[0];
var placeholder = input.getAttribute('placeholder');
/* Create hiddenSpan */
var hiddenSpan = document.createElement('span');
var placeholderText = document.createTextNode(placeholder);
hiddenSpan.appendChild(placeholderText);
/* Style hiddenSpan */
var inputStyles = getComputedStyle(input);
hiddenSpan.style.fontFamily = inputStyles.getPropertyValue('font-family');
hiddenSpan.style.fontSize = inputStyles.getPropertyValue('font-size');
hiddenSpan.style.borderLeftWidth = inputStyles.getPropertyValue('border-left-width');
hiddenSpan.style.paddingLeft = inputStyles.getPropertyValue('padding-left');
hiddenSpan.style.paddingRight = inputStyles.getPropertyValue('padding-right');
hiddenSpan.style.borderRightWidth = inputStyles.getPropertyValue('border-right-width');
hiddenSpan.style.display = 'inline-block';
hiddenSpan.style.opacity = '0';
hiddenSpan.classList.add('hidden');
/* Add hiddenSpan to document body */
body.appendChild(hiddenSpan);
/* Initialise <input> width */
var hiddenSpanStyles = getComputedStyle(hiddenSpan);
var startWidth = parseInt(hiddenSpanStyles.getPropertyValue('width'));
input.style.width = startWidth + 'px';
/* Run reviewWidth() function once */
if (input.value != '') {
reviewWidth(startWidth);
}
/* Add Event Listener to <input> to trigger reviewWidth() function */
input.addEventListener('input',function(){reviewWidth(startWidth);},false);
input {
font-family: arial, sans-serif;
font-size: 0.8em;
padding: 2px;
}
<input type="text" placeholder="Example Placeholder" />
Upvotes: 1