Yuki
Yuki

Reputation: 4183

Grow and shrink the input

I am looking for a way to control the size of my input element in the way similar to divs.

.main {
  width: 100%;
  display: flex;
}

.line {
  min-width: 2rem;
  display: flex;
}

.input {
  flex: 1 1 auto;
  min-width: 0;
}
<div class="main">
  <div class="line">
    <input class="input" />
  </div>
</div>

Here I am expecting that when the view appears the initial input is of size 2rem (padding, margin, border do not matter here) and when you start typing and exceeds the size it grows till it reach the size of main. Any suggestions how I can achieve that?

Upvotes: 0

Views: 339

Answers (3)

Saadi Toumi Fouad
Saadi Toumi Fouad

Reputation: 2829

Here is another solution using the .getBoundingClientRect(), so the idea is to add the text of the input to a p element calculate the width of it then set it as the width of the input, this keeps using the same input instead of content editable trick that a user can press enter and have multiple lines, also can be used in forms...

var txtElement = document.querySelector("#hidden-text");
document.querySelector(".input").oninput = function() {
  txtElement.innerHTML = this.value;
  var width = txtElement.getBoundingClientRect().width;
  this.style.width = width < 100 ? 100 : width + "px";
};
.input {
  width: 100px;
}
#hidden-text {
  display: inline-block;
  position: absolute;
  visibility: hidden;
}
#hidden-text, .input {
  font-size: 16px;
  font-family: Serif;
}
<div class="main">
  <div class="line">
    <input class="input"/>
  </div>
</div>

<p id="hidden-text"></p>

Upvotes: 1

evolutionxbox
evolutionxbox

Reputation: 4122

An example using only CSS and the contenteditable attribute:

.main {
  display: flex;
}

.line {
  display: flex;
}

.input {
  border: 1px solid lightslategray;
  padding: 0.5em;
  margin: 1em;
  min-width: 30ch;
  max-width: 100%;
}
<div class="main">
  <div class="line">
    <p class="input" contenteditable></p>
  </div>
</div>

Upvotes: 2

dave
dave

Reputation: 64705

Probably not the most efficient solution, but you could do something like this:

document.querySelector('.input').addEventListener('input', function(e) {
    let span = document.createElement('span');
    span.innerHTML = e.target.value;
    span.style.visibility = 'hidden';
    span.style.fontSize = '15px';
    document.body.appendChild(span);
    if (span.offsetWidth > e.target.offsetWidth - 10) {
        e.target.style.width = span.offsetWidth + 'px';
    }
    span.parentNode.removeChild(span);
});
.main {
  width: 100%;
  display: flex;
}

.line {
  min-width: 2rem;
  display: flex;
}

.input{
  flex: 1 1 auto;
  min-width: 0;
}
<div class="main">
<div class="line">
  <input class="input"/>
</div>
</div>

Upvotes: 1

Related Questions