'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.
I can't figure out setting of the left side for the inputs / units, anyone help?
Solution 1:[1]
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>
Solution 2:[2]
You can use the size and onInput properties of the input :
const [value, setValue] = useState<string>('');
<input
size={value.length > 3 ? value.length : 3}
onInput={(e) => setValue(e.currentTarget.value)}
type="text"
value={value}
/>;
Solution 3:[3]
You can use a div with content editable instead of an input, so you can expand it as you type. Then you just push the text into the hidden input.
Something like this:
var fakeInput = document.getElementById('yourFakeInput');
var Inputelement = document.getElementById('theRealInput');
fakeInput.onblur = function() {
Inputelement.value = fakeInput.innerHTML;
console.log(fakeInput.clientWidth + 'px');
}
div {
width: auto;
display: inline-block;
}
<div id='yourFakeInput' contenteditable="true">type here...</div>
<input id='theRealInput' type='hidden'>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Val |
Solution 2 | Damien Artero |
Solution 3 | Florin Simion |