Importing React Through the Ages
How and why I import react using a namespace

If you've ever used a controlled input in React, you've already experienced the power of the Control Props pattern—even if you didn't know its name.
But what if you could bring that same flexibility to your own components? That's what the Control Props pattern is all about.
The Control Props pattern lets users of your component take full control over
its state—just like how you can control the value of an <input />
with React
state. By default, your component manages its own state, but if a user provides
a "control prop" (like value
), your component defers to them and simply
"suggests" state changes via callbacks (like onChange
).
This is the same pattern you use every time you write a controlled input:
function MyCapitalizedInput() { const [capitalizedValue, setCapitalizedValue] = useState('') return ( <input value={capitalizedValue} onChange={(e) => setCapitalizedValue(e.target.value.toUpperCase())} /> )}
Here, the <input />
is "controlled" by your state. If you don't provide a
value
prop, it manages its own state. But as soon as you do, you're in charge.
Control props "inverts control" from your component to the developer using it.
For example, you can synchronize two inputs with different transformations:
function MyTwoInputs() { const [capitalizedValue, setCapitalizedValue] = useState('') const [lowerCasedValue, setLowerCasedValue] = useState('') function handleInputChange(e) { setCapitalizedValue(e.target.value.toUpperCase()) setLowerCasedValue(e.target.value.toLowerCase()) } return ( <> <input value={capitalizedValue} onChange={handleInputChange} /> <input value={lowerCasedValue} onChange={handleInputChange} /> </> )}
This isn't just a pattern for inputs. It's used in powerful libraries like downshift and Radix UI Select. These libraries let you control their state from the outside, making them incredibly flexible and easy to integrate into any app.
Here's a simple example of a controlled select using Radix UI:
import * as React from 'react'import { Select } from '@radix-ui/react-select'export default function ControlledSelect() { const [value, setValue] = React.useState('apple') return ( <Select.Root value={value} onValueChange={setValue}> <Select.Trigger> <Select.Value placeholder="Pick a fruit" /> <Select.Icon /> </Select.Trigger> <Select.Portal> <Select.Content> <Select.Item value="apple">Apple</Select.Item> <Select.Item value="orange">Orange</Select.Item> <Select.Item value="grape">Grape</Select.Item> </Select.Content> </Select.Portal> </Select.Root> )}
You control the value from outside the component, and Radix just "suggests"
changes via onValueChange
—a perfect example of the control props pattern in
action. This allows you to programatically control the value of the select,
while still allowing the user to select from the list.
See the official docs for more.
This can actually get a little complex (which is why we have an exercise on it in EpicReact.dev). The reason it's tricky is because you want to support both controlled and uncontrolled modes.
Here's a simple implementation:
function MySelect({ value, onChange }) { const [internalValue, setInternalValue] = useState(value) function handleChange(e) { setInternalValue(e.target.value) onChange?.(e) } return ( <select value={value ?? internalValue} onChange={handleChange}> <option value="apple">Apple</option> </select> )}
This allows you to use the component in both controlled and uncontrolled modes.
There's definitely more to it, but hopefully this gives you an idea of what's going on.
When should you use control props? Reach for this pattern when you want your component to be both easy to use and highly customizable, when you want to let users sync or transform state across multiple components, or when you want to empower users to manage state in the way that fits their app.
Want to master patterns like this—and many more? EpicReact.dev is packed with hands-on workshops, real-world examples, and deep dives into the patterns that make React apps scalable and maintainable. Whether you're a beginner or a seasoned pro, you'll find something to level up your React skills.
Delivered straight to your inbox.
How and why I import react using a namespace
Simplify and speed up your app development using React composition
Why can't React just magically know what to do without a key?
How to improve your custom hook APIs with a simple pattern.