cswork / libraryOpen practice workspace

Articles

UI Coding Interview Guide: Components, State, Accessibility, and Testing

Prepare for UI coding interviews with a practical framework for component design, minimal state, accessibility, edge cases, and behavior-focused testing.

You finish a polished autocomplete with two minutes left. Mouse clicks work, the colors look right, and the data filters correctly. Then the interviewer presses ArrowDown, Enter, and Escape. Nothing behaves as expected.

That is the trap in many UI coding interviews: the visible component is only the surface. Interviewers are also evaluating how you model behavior, decide where state belongs, preserve keyboard and focus semantics, test the user contract, and explain what you would improve with more time.

This guide gives you a repeatable workflow for turning those prompts into a small, complete, defensible UI.

A strong UI coding solution connects a clear component model to observable, accessible behavior.

Quick Verdict

Build the smallest complete experience, not the largest feature set. Clarify the behavior, define minimal state, ship the happy path, add the keyboard and focus contract, test the highest-risk interactions, and narrate any deliberate trade-offs.

A strong candidate can answer four questions at any moment: What is the user doing? Which component owns that behavior? What state is the source of truth? How will I prove it works?

Framework fluency matters, but a finished accordion with semantic buttons, correct state, keyboard operation, and two meaningful tests is usually a better interview artifact than an elaborate component with fragile behavior.

What Is a UI Coding Interview?

A UI coding interview is a timed implementation round where you build an interactive component or small product surface in a browser. The prompt might be an autocomplete, tabs, modal, data table, carousel, file explorer, or toast system.

Atlassian's published Frontend Engineering Interview Guide, for example, describes browser coding as building a simple interactive interface in a runnable environment. Its 60-minute coding rounds assess code quality, conceptual thinking, communication, and testing. Formats vary by company, so treat your recruiter instructions as the source of truth.

RoundPrimary deliverableMain question
DSA codingCorrect algorithmCan you reason about data structures and complexity?
UI codingWorking interactive componentCan you turn product behavior into usable code?
Frontend system designArchitecture and trade-offsCan you design a larger frontend system?
Take-homeReviewable repositoryCan you deliver a polished solution with more time?

For architecture-only rounds, use the Front-End System Design Interview Guide.

What Interviewers Score

SignalStrong evidenceCommon miss
BehaviorCore interactions and edge states workOptimizes styling before functionality
ComponentsBoundaries follow responsibilities and data flowOne giant component or premature abstraction
StateOne source of truth with derived values calculatedDuplicated state drifts out of sync
AccessibilitySemantic controls, keyboard behavior, visible focusMouse-only interaction with decorative ARIA
TestingTests observable behavior and risky transitionsTests implementation details or skips verification
CommunicationClarifies assumptions and explains trade-offsCodes silently until time expires

A 55-Minute UI Coding Interview Plan

TimeActionVisible output
0-5 minClarify behaviors, data, constraints, and prioritiesShort acceptance contract
5-10 minSketch components, state, and key eventsSimple implementation map
10-30 minBuild the semantic happy pathWorking mouse and basic keyboard flow
30-40 minAdd focus behavior and loading, empty, and error statesComplete interaction states
40-50 minTest the highest-risk user journeysTwo or three behavior tests
50-55 minRun, review, and explain remaining trade-offsClean demo and prioritized follow-ups

This is a practice framework, not a universal company schedule. If the interviewer gives you 40 minutes, compress styling and secondary edge cases before sacrificing the core user contract.

Keep the loop visible: clarify, model, build, make accessible, test, and explain.

Case Study: Build an Accessible Autocomplete

Autocomplete is an excellent practice problem because a small visual surface hides meaningful decisions about component boundaries, state, asynchronous data, keyboard navigation, focus, and testing.

The component contract should describe behavior before it describes implementation.

1. Clarify the Behavior Contract

Before coding, ask whether data is local or remote, whether free-form text is allowed, when suggestions open, whether the first result becomes active automatically, and what selection should do. Then confirm the priority order if time runs short.

AreaAgreed behavior
InputTyping filters city suggestions
PointerClicking an option selects it and closes the popup
KeyboardArrows move the active option; Enter selects; Escape closes
StatesLoading, no results, and request failure are distinguishable
AccessibilityThe input has a visible label and exposes popup state
TestTyping, keyboard selection, and dismissal are verified

2. Choose Component Boundaries

Start with one owner, such as Autocomplete, that coordinates input, popup state, active option, and selection. Extract OptionsList or Option when a child has a coherent responsibility, repeated markup, or a useful prop contract.

Do not split every div into a component. An interviewer wants readable ownership, not the highest component count. Keep rapidly changing local UI state near the smallest subtree that needs it.

3. Model Minimal State

const [query, setQuery] = useState("");
const [isOpen, setIsOpen] = useState(false);
const [activeIndex, setActiveIndex] = useState(-1);
const [selectedId, setSelectedId] = useState(null);

const visibleOptions = options.filter(option =>
  option.label.toLowerCase().includes(query.toLowerCase())
);

query, isOpen, activeIndex, and selectedId represent independent user-visible decisions. visibleOptions is derived from existing inputs and does not need another state setter.

React's state-structure guidance recommends avoiding redundant and duplicated state because synchronized copies create more ways for the UI to become inconsistent. Also reset activeIndex deliberately when the query or result set changes so it never points beyond the list.

4. Build Semantics Before Decorative ARIA

Use native elements for native behaviors: a real label, input, and button. MDN's ARIA guidance says to prefer the correct semantic HTML element when it already supplies the required semantics and behavior.

An autocomplete is a custom composite widget, so its extra relationship still needs to be expressed:

<label htmlFor="city">City</label>
<input
  id="city"
  role="combobox"
  aria-autocomplete="list"
  aria-expanded={isOpen}
  aria-controls="city-options"
  aria-activedescendant={activeOptionId || undefined}
/>

{isOpen && (
  <ul id="city-options" role="listbox">
    {visibleOptions.map(option => (
      <li
        id={`city-option-${option.id}`}
        role="option"
        aria-selected={option.id === activeId}
        key={option.id}
      >
        {option.label}
      </li>
    ))}
  </ul>
)}

Names, IDs, and selection logic must match your real implementation. Adding role="combobox" without the expected state and keyboard behavior makes the interface more confusing, not more accessible.

5. Implement the Keyboard and Focus Contract

The W3C combobox pattern defines the essential relationships and interaction model. For an editable list autocomplete, keep DOM focus on the input, expose the active option with aria-activedescendant, and make selection visually distinct.

InputExpected result
ArrowDownOpen the popup when appropriate and move to the next option
ArrowUpMove to the previous option according to the agreed boundary behavior
EnterCommit the active option and close the popup
EscapeDismiss the popup without accidentally committing a new option
TabFollow normal page focus order; do not create a keyboard trap

Do not capture every key. Standard text-editing keys should continue to work inside the input. When an option is selected by pointer, verify that blur and click ordering does not close the popup before selection is processed.

6. Handle Async and Edge States

If suggestions come from an API, show loading, empty, and error states without confusing them. Protect against stale responses: a slow request for sa should not overwrite a newer response for san. Cancellation or a request sequence ID can preserve the latest-query contract.

Also decide what happens when results shrink while an option is active, the user clears the input, an option is disabled, or the selected item disappears. State transitions are part of correctness, not optional polish.

7. Test What the User Can Observe

Testing Library's guiding principle is to make tests resemble real use. Querying by role and accessible name checks the same interface exposed to users, while user-event models complete interactions rather than firing one isolated DOM event.

const user = userEvent.setup();
render(<CityAutocomplete options={cities} />);

const input = screen.getByRole("combobox", { name: /city/i });
await user.type(input, "san");

expect(
  screen.getByRole("option", { name: "San Francisco" })
).toBeVisible();

await user.keyboard("{ArrowDown}{Enter}");
expect(input).toHaveValue("San Francisco");

Add one test for Escape or the empty state, then run the component manually with only a keyboard. Automated tests are useful evidence, but they do not replace checking visible focus, zoom, responsive layout, or a real screen-reader flow.

Common UI Coding Interview Prompts

ComponentState challengeAccessibility or test focus
AccordionSingle versus multiple open panelsButton semantics, expanded state, Enter and Space
TabsActive tab and mounted panel stateArrow navigation, selected tab, panel relationship
ModalOpen state and action resultInitial focus, focus containment, Escape, focus return
AutocompleteQuery, active option, selection, async statusCombobox roles and keyboard selection
Data tableSort, filters, pagination, selectionHeaders, sort state, loading and empty states
CarouselCurrent slide and autoplayNamed controls, pause behavior, announcement restraint
Toast systemQueue, timers, and removalAnnouncements, pause, deterministic timer tests
File treeExpansion, selection, and hierarchyTree keyboard model and focus movement

Do not memorize eight full implementations. Practice the same analysis on each: acceptance contract, owner, minimal state, semantics, keyboard path, edge states, and one high-risk test.

Common UI Coding Interview Mistakes

  • Coding before agreeing on behavior. A beautiful solution can still implement the wrong product contract.
  • Duplicating derived state. Filtered results, counts, and boolean flags often belong in render-time calculations.
  • Making accessibility a final ARIA pass. Element choice, focus, and keyboard behavior shape the architecture from the start.
  • Testing private implementation details. A refactor should not break a test when user-visible behavior stays the same.
  • Spending the last minute adding features. Run the current solution, fix obvious failures, and explain the next priority.

A 5-Day UI Coding Practice Plan

DayComponentPractice goal
1AccordionSemantic controls, minimal state, keyboard activation
2TabsComponent contract, focus model, selected state
3AutocompleteAsync states, active option, role-based tests
4ModalFocus entry, containment, Escape, and return
5Timed mockComplete one unfamiliar prompt in 55 minutes

Narrate your assumptions, attempt the prompt before reading any solution, and review where your state or test plan became unclear.

If React behavior itself is the weak area, pair this plan with React Interview Questions for Senior Frontend Engineers.

UI Coding Interview FAQ

Can I use React in a UI coding interview?

It depends on the company and prompt. Some browser rounds allow the framework you use most confidently, while others require vanilla JavaScript to evaluate DOM and language fundamentals. Confirm the environment, allowed packages, starter code, and expected testing setup before the interview.

How much accessibility should I implement under time pressure?

Start with native semantic elements, a visible label, logical keyboard access, and visible focus. For a custom composite such as a combobox, implement the role, state, relationship, and key behavior together. If time prevents a complete pattern, explain the exact gap rather than claiming accessibility is finished.

Should I write tests before or after the component?

Either can work if you keep a clear behavior contract. A practical timed approach is to define the highest-risk cases first, build a thin working path, then encode two or three user-visible behaviors as tests. If the company explicitly expects TDD, follow that instruction and begin with the contract test.

What if I cannot finish the UI coding problem?

Keep the current version runnable. Demonstrate the completed path, identify the first failing requirement, and explain the next implementation and test step. A coherent, tested core with honest prioritization gives the interviewer more evidence than several half-connected features or a last-minute rewrite.

Final Takeaway

A UI coding interview is not a race to produce the most JSX. It is a compact product-engineering exercise: clarify behavior, assign ownership, model one source of truth, preserve the keyboard and focus contract, and test what a user can observe.

Repeating the same decision loop across unfamiliar components is what makes your interview execution faster and more reliable.

Sources and Further Reading