React: how to make an input only as wide as the amount of text provided?
Here is an approach from plain HTML/CSS and a working snippet , hidding the value typed inside a span
behind the input
set in an absolute
position
. CSS can make both span
and input
matching the same lenght/width. Stretching/collapsing a parent (label
) will finish the job.
In the courtesy of @silvenon you may also find a react sample below the snippet
var val = document.querySelector('#test');
let tpl = document.querySelector('#tpl');
let text = val.value;
tpl.textContent= text;
val.addEventListener("input", function () {// onchange ...
let text= val.value;
//console.log(text);
tpl.textContent= text;
});
label {
display: inline-block;
position: relative;
min-width: 2em;
min-height: 1.4em;
}
#tpl {
white-space: pre;
/* max-width : could be wised to set a maximum width and overflow:hidden; */
}
#test {
font-family: inherit;
font-size: inherit;
position: absolute;
vertical-align: top;
top: 0;
left: 0;
width: 100%;
background: white;
}
<label><span id="tpl"></span><input id='test' value="Some test to try" ></label>
Auto-scaling input to width of value in React
After a lot of fiddling around, I found a solution!
import React, { useState, useRef, useEffect } from 'react';
export default () => {
const [content, setContent] = useState('');
const [width, setWidth] = useState(0);
const span = useRef();
useEffect(() => {
setWidth(span.current.offsetWidth);
}, [content]);
const changeHandler = evt => {
setContent(evt.target.value);
};
return (
<wrapper>
<span id="hide" ref={span}>{content}</span>
<input type="text" style={{ width }} autoFocus onChange={changeHandler} />
</wrapper>
);
};
To get a reference to the #hide
span I employ useRef
. Then, the width
state variable can be updated via the function defined inside useEffect
, which gets called everytime content
changes.
I also had to switch the display: none
in the css of #hide
for position: absolute
and opacity: 0
, as otherwise targetRef.current.offsetWidth
would always be 0.
Here's a working demo.
Adjust width of input field to its input
It sounds like your expectation is that the style be applied dynamically to the width of the textbox based on the contents of the textbox. If so you will need some js to run on textbox contents changing, something like this:
<input id="txt" type="text" onkeypress="this.style.width = ((this.value.length + 1) * 8) + 'px';">
Note: this solution only works when every character is exactly 8px
wide. You could use the CSS-Unit "ch" (characters) which represents the width of the character "0" in the chosen font. You can read about it here.
How to make an automatic increase in the width of the text input field depending on the number of lines?
onLayout={(event) => {
if (textInputHeight === 0) {
setTextInputHeight(event.nativeEvent.layout.height);
}
}}
onContentSizeChange={(event) => {
setTextInputHeight(event.nativeEvent.contentSize.height);
}}
width:auto for input fields
An <input>
's width is generated from its size
attribute. The default size
is what's driving the auto width.
You could try width:100%
as illustrated in my example below.
Doesn't fill width:
<form action='' method='post' style='width:200px;background:khaki'>
<input style='width:auto' />
</form>
Fills width:
<form action='' method='post' style='width:200px;background:khaki'>
<input style='width:100%' />
</form>
Smaller size, smaller width:
<form action='' method='post' style='width:200px;background:khaki'>
<input size='5' />
</form>
UPDATE
Here's the best I could do after a few minutes. It's 1px off in FF, Chrome, and Safari, and perfect in IE. (The problem is #^&* IE applies borders differently than everyone else so it's not consistent.)
<div style='padding:30px;width:200px;background:red'>
<form action='' method='post' style='width:200px;background:blue;padding:3px'>
<input size='' style='width:100%;margin:-3px;border:2px inset #eee' />
<br /><br />
<input size='' style='width:100%' />
</form>
</div>
Why is my Text Input getting activated only at the width of PlaceHolder?
Try this simple solution,
<TextInput style={[customStyles.text, { flex: 1 }]} {...otherProps} />
Minimal input width growing with value
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>
React Native Text Input fields not taking full width even though flex: 1
just try this with only one TextInput
return (
<View style={styles.container}>
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : null}
style={{ flex: 1, width: "100%" }}
>
<ScrollView style={styles.inner}>
<TextInput
style={styles.input}
placeholder="Postal Code"
value={"fdf"}
/>
</ScrollView>
</KeyboardAvoidingView>
</View>
);
It will surely work :)
Related Topics
How to Have a Horizontal Multiple Colour Gradient on Text Using CSS3/HTML 5
Break Line on White Space Between Words
Box-Shadow Only on Left and Right
:Hover Not Working on Svg When Svg Is in External File
Position Element at Bottom Right Corner of Current Window
How to Merge .CSS Files with SASS (Or Other Tool)
When and How Do Browsers Render <Style> Tag in <Body>
Scss Target Class Before :Hover
Print Contents of a Modal Popup
Is Sizing Fonts Using "Em" Still Relevant
What Is Appropriate Ordering of CSS Selector? Eg P.Class or .Class P
Sass: Set Variable at Compile Time
How to Get Attribute Value Using Selenium and CSS
Css: Adding a Border Changes the Background-Color (!)