Design System Glossary

Controlled vs Uncontrolled Components

Controlled components hold their state outside themselves — a parent manages the value, and the component is told what to render. The parent listens for change events and updates the value. Uncontrolled components manage their own internal state — set it once, and the component handles it from there.

A controlled text input in React looks like:

<Input value={inputValue} onChange={(e) => setInputValue(e.target.value)} />

Uncontrolled:

<Input defaultValue="initial" />

In a Design System, this choice shapes the whole component API. Controlled components are more predictable — the parent always knows the current state. They're easier to validate, combine with other logic, and test. But they require more boilerplate.

Uncontrolled components are simpler for one-off uses. Drop them in, they work. But coordinating across multiple uncontrolled components gets messy — you can't easily validate a form's state without querying the DOM.

Most modern systems offer both. A Form component in a Design System might use controlled inputs internally (to power validation) but expose a simple uncontrolled API for simple forms. This is a form of composability: let callers choose their complexity level.

The trap: picking one pattern and enforcing it everywhere. Controlled works best for complex, data-bound UIs; uncontrolled works best for one-off, simple inputs. A good Design System clarifies which is the default and when to break it.

Related: Component API · Component states · Composability · Component