In UI interviews, you’re often asked to build reusable components like a Dropdown, Tabs, or a Modal. The real test isn’t just “can you make it work once” — it’s whether your API design feels scalable in a real codebase. Interviewers want to see if another developer could pick up your component, plug it in, and extend it without rewriting everything. In this guide, we’ll walk through patterns that signal maturity and thoughtfulness — the kind of answers that stand out in a high-pressure interview.
1. Controlled vs uncontrolled
Show that you know both patterns. Controlled = parent manages state. Uncontrolled = component manages state.
<!-- Controlled input -->
<TextField value={value} onChange={setValue} />
<!-- Uncontrolled input with default -->
<TextField defaultValue="hello" onChange={v => console.log(v)} />2. Composition over configuration
Instead of a million props, show you’d allow composition. This always earns points.
<!-- ❌ Too rigid -->
<Modal title="Delete?" showCancel showConfirm />
<!-- ✅ Flexible, scales with content -->
<Modal>
<Modal.Header>Delete item</Modal.Header>
<Modal.Body>This cannot be undone.</Modal.Body>
<Modal.Footer>
<Button variant="ghost">Cancel</Button>
<Button variant="danger">Delete</Button>
</Modal.Footer>
</Modal>3. Event naming & payloads
Interviewers look for clarity. Don’t just return raw events — return useful detail.
function Select({ value, onChange }) {
// onChange({ value, label, reason })
}4. Accessibility baked in
- Correct roles (
role="dialog",role="tablist"). - Keyboard handling (Escape, Tab, Arrow keys).
- Focus management (send focus in, restore on close).
<div role="dialog" aria-modal="true" aria-labelledby="dlgTitle">
<h2 id="dlgTitle">Confirm Delete</h2>
</div>5. Styling surface
Show you’d make styling flexible but not chaotic.
<Button variant="danger" size="lg">Delete</Button>.btn {
--btn-bg: #1f2937;
--btn-fg: #fff;
background: var(--btn-bg);
color: var(--btn-fg);
}6. Async state awareness
Front-end is async by nature. Interviews love when you call this out.
<Button onClick={async () => {
setLoading(true);
await api.delete();
setLoading(false);
}}>
{loading ? "Deleting..." : "Delete"}
</Button>7. Practice drill
Take any common widget (Tabs, Dropdown, or Modal) and practice evolving it step by step. The goal isn’t a production-ready library — it’s to show layered thinking under interview pressure.
- Start with MVP. Build the absolute minimum: one tab switches content, one dropdown selects an item, one modal opens and closes. ✅ Shows you can ship fast.
- Add controlled vs uncontrolled options. Controlled = parent passes state + callback. Uncontrolled = component manages its own state. ✅ Signals you understand real-world flexibility.
- Add clear events. Don’t just fire raw DOM events — surface meaningful ones like
onChange,onSelect, oronOpenChange. ✅ Interviewers look for APIs that would scale in a team. - Layer in accessibility (a11y). Add roles (
role="tablist",role="dialog"), keyboard handling (Arrow keys, Escape), and focus management. ✅ Easy bonus points — most candidates forget this. - Make it styleable. Add a
variantprop (e.g.,primary,danger) or expose CSS variables. ✅ Shows you think about design systems, not just isolated code.
💡 Pro tip: narrate your steps out loud (“First I’ll make it work, then I’ll add a controlled mode, then keyboard support”). This makes your process clear and interviewers will often guide you toward what they care about most.
Wrap-up
In a UI interview, don’t stop at “it works.” Explain how the API scales: what’s controlled vs uncontrolled, what events fire, and how consumers style/compose it. That’s what separates a quick demo from a component a team can actually ship.
- Name the contract: “Props:
open,defaultOpen,onOpenChange. Events:onSelect. Slots:trigger,content.” - Call out a11y & keyboard: roles, focus management, Escape/Arrow keys, visible focus.
- Show the styling story: variants or CSS variables; how a design system would theme it.
- Mention performance: lazy mount, avoid layout thrash, prefer
transform/opacityfor animations. - State your trade-offs: “I kept state local for simplicity; I’d expose a controlled mode for complex use.”
👉 Keep narrating as you go. If you run out of time, close with: “MVP works; next I’d add focus trap, type-ahead, and a controlled mode with onOpenChange.”
Want focused practice? Try the coding drills next, or skim client-side system design patterns.