Component API Guides
Designing component APIs that are flexible without being chaotic.
Components are the air frontend engineers breathe — we pull them from libraries, design systems, and each other's code all day. Some feel effortless; others fight you at every prop. That feeling isn't luck — it comes from how the component's API was designed. This lesson is five principles for getting it right.
Good vs. bad component experience
We've all had both reactions to a component: “this is a joy” or “why won't this just work?” Those feelings trace back to concrete traits. Tap to compare:
Make impossible states impossible
Take an Alert with three boolean props — success, warning, danger. Each alone is fine. But nothing stops a consumer from passing two at once — and now the component is in a state you never intended. Build the bug, then watch the fix:
The fix is to collapse the mutually-exclusive booleans into a single variant prop. A prop can only hold one value, so the conflicting combination becomes unrepresentable — the bug is designed out of existence.
// ✕ allows success + warning at the same time
<Alert success warning />
// ✓ one value, no conflicts possible
<Alert variant="warning" />Less is more
We've all met the component with thirty props that tries to do everything. It's powerful for one exact use case and miserable for every other — you can never remember which props produce which result, so you're forever flipping between the page and the component's source.
A single UserProfileCard juggling the avatar, the edit modal, drag-and-drop upload, dark-mode logic, and the status badge. Dozens of props, one giant blob of responsibility.
<UserProfileCard
avatarRounded avatarSize="lg" editable
onAvatarClick onAvatarDelete showStatus
statusColor followsDarkMode dragToUpload
/* 20 more props */
/>Be consistent
The same idea should always wear the same name. If a button uses disabled, the input shouldn't use enabled={false} and the dropdown isDisabled. They mean the same thing — so pick one name and keep it everywhere. Sort these into the consistent naming bucket:
Use types if possible
Type-safety (TypeScript, PropTypes) does double duty. It stops consumers from passing invalid values, and it teaches them the API right in the editor — autocomplete lists every valid option, no doc-diving needed. Pick a value, or try an invalid one:
Pair this with principle 1: an enum type for variant both documents the four allowed values and makes the impossible combinations a compile error.
Be clear
A clever prop name feels cute for a day and confuses everyone after. The classic trap is a name like slim — what does it actually do? Guess:
Name a prop after what it controls. If it removes the margin, call it noMargin (or expose margin). Boring names win — they're predictable, and they stop people inventing tight, fluffy, cozy variants to match a fuzzy original.
<Alert slim /> // ✕ slim what?
<Alert noMargin /> // ✓ obvious
<Button padding="lg" /> // ✓ named after what it controlsCheck your understanding
Design challenge
Audit a component you use often (a Button, Modal, or Table):
- Find any booleans that could be combined into one
variantenum. - Spot a prop name that's clever but unclear — rename it.
- Check it uses the same vocabulary (
disabled,size,onChange) as its siblings.
- →A component's “feel” comes from its API: works out of the box, consistent, intuitive, customizable, predictable.
- →Make impossible states impossible — fold conflicting booleans into one enum prop.
- →Less is more — too many props is a smell; compose small, single-responsibility parts.
- →Be consistent and be clear — same concept, same name; name props after what they control.
- →Use types — they block invalid values and teach the API through autocomplete.