2

In a grid, columns can grow and shrink to fill up available space, and do this proportional to the content widths of each column. See the <span> part of the example below.

I would like to make <input> columns grow and shrink too, in exactly the same way the <span>s do.

.grid {
  display: grid;
  grid-template-columns: repeat(2, auto);
  width: 300px;
}

.column {
  border: 1px solid gray;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
<h3>span</h3>
<div class="grid">
  <span class="column" contenteditable></span>
  <span class="column" contenteditable></span>
</div>
<h3>input</h3>
<div class="grid">
  <input class="column" type="text">
  <input class="column" type="text">
</div>

Current behaviour:

enter image description here

Wanted behaviour:

enter image description here

The fact that the columns should change size depending on the ratio between the two columns' widths is the most important goal (in the demo, the <span>s already do this)

I have tried setting min-width and width of the inputs based on the HTML-width of their value, calculated using the createElement method here. But when min-width or width are set, the size of the input can't be changed by the grid anymore, instead the grid resizes columns over the top of the input and the ellipses never show.

I think setting widths is the wrong way to do this anyway, can CSS figure out how much content an input has?

theonlygusti
  • 11,032
  • 11
  • 64
  • 119
  • input doesn't have content, it has value. – Temani Afif Sep 12 '21 at 10:24
  • @TemaniAfif which is rendered as if it were content (in fact some browsers like MS Edge even show it in Inspect Element as a shadow DOM child). I am hoping to find a way in CSS to treat the input element's value as if it were content. – theonlygusti Sep 12 '21 at 10:28

1 Answers1

2

input have a size set by defaut (from the attribute size) but it can be overridden via width.

You can set a small value to size , alike 1 or 2, then use javascript to resize it according to its content.

here is an idea using hidden span where

  • the value of input are mirrored inside (mind font-size and font-family, ...),
  • retrieve the width of the span then apply it back to the input.

// deserves to be rewritten . inspired from https://stackoverflow.com/questions/64092841/react-how-to-make-an-input-only-as-wide-as-the-amount-of-text-provided/64094013#64094013
let val = document.querySelectorAll("#text1, #text2, #text3, #text4");
let tpl = document.querySelectorAll("#sptext1, #sptext2, #sptext3, #sptext4");

function resizeIpt() {
  let text1 = val[0].value;
  let text2 = val[1].value;
  let text3 = val[2].value;
  let text4 = val[3].value;
  tpl[0].textContent = text1;
  tpl[1].textContent = text2;
  tpl[2].textContent = text3;
  tpl[3].textContent = text4;
}
let ipt = document.querySelectorAll('.grid input[type="text"]');
for (let i = 0; i < ipt.length; i++) {
  ipt[i].addEventListener("input", function() {
    // onchange ...
    tpl[i].textContent = val[i].value;
    val[i].style.width = "unset"; /* reset actual width */
    resizeIpt;
  });
}
window.onload = resizeIpt;
* {
  box-sizing: border-box;
}

.grid {
  display: grid;
  grid-template-columns: repeat(2, auto);
  /* justify-content: left; or start will shrink the columns if contents together are  smaller than 300px of width */
  width: 300px;
  background: #bee
}

.column {
  border: 1px solid gray;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: clamp(2em, min-content, 100%);
  padding: 0 0.5em;
  font-size: inherit;
  font-family: inherit;
}

span[id].column {
  height: 0;
  overflow: hidden;
  border: none;
}
<h3>span</h3>
<div class="grid">
  <span class="column" contenteditable>let it be a really much too long text here </span>
  <span class="column" contenteditable>short</span>
</div>

<h3>input</h3>
<div class="grid">
  <span id="sptext1" class="column"></span>
  <span id="sptext2" class="column"></span>
  <input class="column" size="2" id="text1" type="text" value='let it be a really much too long text here'>
  <input class="column" size="2" id="text1" type="text" value="short">
</div>

<h3>input</h3>
<div class="grid" style="font-family:monospace;">
  <span id="sptext3" class="column"></span>
  <span id="sptext4" class="column"></span>
  <input class="column" size="2" id="text3" type="text" value="short">
  <input class="column" size="2" id="text4" type="text" value='let it be longer'>
</div>

inspired from React: how to make an input only as wide as the amount of text provided?

G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129