Frontend System Design/Component API Design
Lesson 9 of 17 · Episode 9

Component API Guides

Designing component APIs that are flexible without being chaotic.

Component APIProps designDX
Watch on YouTube ↗

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.

Why it matters

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:

Why interviews love this
Everyone has used a button, a dropdown, a modal — so a UI-component prompt is easy to understand but rich in detail. Expect component design to take a big chunk of a frontend system-design interview.
Principle 1

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:

<Alert /> API
Set the props
<Alert />
Renders
Heads up — this is a primary alert.
Toggle two booleans on at once and watch the API fall apart — then switch to Single variant.

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.

from impossible to impossible-by-design
// ✕ allows success + warning at the same time
<Alert success warning />

// ✓ one value, no conflicts possible
<Alert variant="warning" />
The principle
When a set of props can combine into a state you don't want, redesign the API so that state can't be expressed. Often that means one enum prop instead of several booleans.
Principle 2

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.

hard to remember, hard to reuse
<UserProfileCard
  avatarRounded avatarSize="lg" editable
  onAvatarClick onAvatarDelete showStatus
  statusColor followsDarkMode dragToUpload
  /* 20 more props */
/>
Tip
A component drowning in props is a code smell. The cure is usually composition — break it into smaller components, each with a single responsibility and a small, memorable API.
Principle 3

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:

0/5 sorted
Button, Input, and Select all use `disabled`
`disabled` on Button but `enabled={false}` on Input
`onChange` across every form control
`isOpen` on Modal but `visible` on Drawer
`size="sm|md|lg"` everywhere it applies
Watch out
Consistency is the easiest principle to state and the easiest to forget — the cracks only show as the codebase grows. Decide the vocabulary early and hold the line.
Principle 4

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:

Editor — autocomplete from the type
<Alert variant="|" />
variant: Variant
Pick a suggestion — the type lists every valid option.

Pair this with principle 1: an enum type for variant both documents the four allowed values and makes the impossible combinations a compile error.

Principle 5

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.

clear beats clever
<Alert slim />        // ✕ slim what?
<Alert noMargin />    // ✓ obvious
<Button padding="lg" /> // ✓ named after what it controls
Practice

Check your understanding

Q1Multiple choice
A Toast has booleans `info`, `success`, and `error`. Two can be passed at once. Best fix?
Q2Sort each scenario
Which principle does each choice serve?
Renaming `slim` to `noMargin`
Using `disabled` on every control
Calling the spacing prop `padding`, not `cozy`
`onChange` everywhere instead of `onUpdate` here and `onEdit` there
Q3Multiple choice
A component has 28 props and everyone keeps re-reading its source. What does that signal?
Try it yourself

Design challenge

Audit a component you use often (a Button, Modal, or Table):

  1. Find any booleans that could be combined into one variant enum.
  2. Spot a prop name that's clever but unclear — rename it.
  3. Check it uses the same vocabulary (disabled, size, onChange) as its siblings.
Key takeaways
  • 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.
← Previous
8. RADIO — Optimizations & Deep Dive
Next →
10. Customizing Component Appearance