I want to have an input whose width adapts to fit its content.
I'm trying to implement this answer to a similar question, but using React:
import React, { useState } from 'react';
export default () => {
const [content, setContent] = useState('');
const [width, setWidth] = useState(0);
const changeHandler = evt => {
setContent(evt.target.value);
};
return (
<wrapper>
<span id="hide">{content}</span>
<input type="text" autoFocus style={{ width }} onChange={changeHandler} />
</wrapper>
);
};
The problem is I don't know how to then query the width of the span, in order to then change the width of the input (using setWidth
).
How can I achieve this?
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 evaluate to 0.
Here's a working demo.