Search code examples
cssreactjsinputlayoutflexbox

Minimal input width growing with value


I have a form in react app which has

  • labels on the left side
  • inputs for values + units on the right side

All elements uses display:flex by default.

I need the input size to have a minimum width 30px, but in case the input number is longer (i.e. 8 digits), I need the input to stretch itself up to his maximum width 80px, while still being aligned on the right.

Here is a fiddle of the form https://codepen.io/anon/pen/MrweLQ

HTML of row:

<div class="formRow formRowEven">
    <div class="label">Long value</div>
    <div class="valueWrapper">
      <div class="value">
        <input value="12345678"/>
      </div>
      <div class="unit">min</div>
    </div>
  </div>

CSS:

.formRow {
  display: flex;
  flex-direction: row;
  flex: 1 1;
}

.label {
  flex: 1 1;
}
.valueWrapper {
  display: flex;
  flex-direction: row;
}

.value {
  display: flex;
  margin-right: 5px;
  min-width: 0;
  max-width: 80px;
  display: flex;
  justify-content: flex-end;
}

input {
  color: #fff;
  min-width: 0;
  display: flex;
  flex: 1 0 30px;
  border-width: 0 0 1px;
  border-color: #ccc;
  border-style: solid;  
}

And here is an image of the ideal state.

enter image description here

I can't figure out setting of the left side for the inputs / units, anyone help?


Solution

  • As @DanFarrell said, <input /> in html is not designed for inline display.

    Use <span /> with contentEditable="true", with modified codepen https://codepen.io/valuis/pen/LeVrbx

    and code snippet:

    @import url(//fonts.googleapis.com/css?family=Roboto:400,300);
    @import url(//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css);
    
    html {
      font-size: 17px;
    }
    
    *, *:before, *:after {
      box-sizing: border-box;
    }
    
    body {
      background: #111;
      font-family: 'Roboto';
      -webkit-font-smoothing: antialiased;
      text-rendering: optimizeLegibility;
    }
    
    .wrapper {
      background: #48435C;
      margin: 2rem auto 0;
      max-width: 80%;
      color: #fff;
      border: 1px solid #ddd;
      padding: 20px 0;
    }
    
    h1 {
      padding: 0 30px;
    }
    
    .formRow {
      padding: 10px 30px;
    }
    
    .formRowOdd {
      background: #383850;  
    }
    
    /* LAYOUT */
    .formRow {
      display: flex;
      flex-direction: row;
      flex: 1 1;
    }
    
    .label {
      display: flex;
      flex: 1 1;
    }
    .valueWrapper {
      display: flex;
      flex-direction: row;
    }
    
    .value {
      display: flex;
      margin-right: 5px;
      min-width: 0;
      max-width: 80px;
      display: flex;
      justify-content: flex-end;
    }
    
    span {
      display: flex;
      color: #fff;
      background: transparent;
      text-align: right;
      min-width: 0;
      overflow: hidden;
      max-width: 80px;
      flex: 1 0 30px;
      border-width: 0 0 1px;
      border-color: #ccc;
      border-style: solid;  
    }
    <div class="wrapper">
      <h1>Form</h1>
      <div class="formRow formRowOdd">
        <div class="label">Short value</div>
        <div class="valueWrapper">
          <div class="value">
            <span contentEditable="true">123</span>
          </div>
          <div class="unit">min</div>
        </div>
      </div>
      <div class="formRow formRowEven">
        <div class="label">Long value</div>
        <div class="valueWrapper">
          <div class="value">
            <span contentEditable="true">1234567</span>
          </div>
          <div class="unit">min</div>
        </div>
      </div>
      <div class="formRow formRowOdd">
        <div class="label">Value to be filled</div>
        <div class="valueWrapper">
          <div class="value">
            <span contentEditable="true" />
          </div>
          <div class="unit">min</div>
        </div>
      </div>
    </div>