React applications are built as trees of components. While we often use components as self-closing tags, React also supports opening and closing tags — enabling component composition. This allows us to pass content between tags and access it via the children prop.
Instead of passing a label prop, we can place content between the component’s tags:
<InputWithLabel ...>
Search:
</InputWithLabel>Inside the component, we access this content using children:
const InputWithLabel = ({ id, value, onInputChange, children }) => (
<>
<label htmlFor={id}>{children}</label>
<input id={id} value={value} onChange={onInputChange} />
>
);This makes the component flexible and composable, allowing us to inject strings, HTML elements, or even other React components.
To focus an input field declaratively, we can use the autoFocus attribute:
<input autoFocus />To make this behavior configurable, we pass a prop like isFocused:
<InputWithLabel isFocused />And use it inside the component:
<input autoFocus={isFocused} />For more control, we can set focus programmatically using useRef and useEffect:
const inputRef = React.useRef();
React.useEffect(() => {
if (isFocused && inputRef.current) {
inputRef.current.focus();
}
}, [isFocused]);Then assign the ref to the input element:
<input ref={inputRef} ... />useRef.ref attribute.useEffect to trigger focus when isFocused changes.ref.current and call focus().React’s component composition and children prop allow for flexible, expressive UI design. Combined with imperative access via useRef, we can build components that are both declarative and interactive. These patterns are essential for building reusable, scalable, and dynamic React applications.