ESC

Type to search the knowledge base.

Frontend LLD on a Whiteboard

Box the UI, name the state, walk the data flow, leave CSS last. A 45-minute low-level design method for frontend interviews.

advanced6 min read
  • interview
  • lld
  • system-design
  • frontend

Frontend LLD is the round with a whiteboard (or a doc) and one feature, not a cluster diagram and not a repo. You lose when you spend twenty minutes on flex and radius while nobody can point at a box and say what state lives in it.

This is a 45-minute method: box the UI, name the state, walk the data flow, leave CSS last. Accessibility is the last five minutes. It is not frontend system design (cache, SSR, scale). It is not machine coding (a working slice in an editor). It is not whiteboarding one component API. LLD is the feature as boxes, ownership, events, and one network contract.

Key takeaways

  • Draw regions and names before fields, files, or CSS.
  • State is ownership: source of truth, derived, who writes.
  • Walk one user action from event to render, then one failure.
  • CSS last. Keyboard, focus, and names get the last five minutes.
  • Stretch goes on a parking list. Do not decorate an unnamed model.

Box the UI, name the state, walk the data flow, leave CSS last

Run this sequence even if you have built the feature before. The board is the artifact they grade.

45-minute procedure

  1. Restate and cut (0-5). Users, happy path, non-goals. Write an MVP checklist the interviewer can nod at.
  2. Box the UI (5-12). Rectangles for regions. Label each with a component name. Mark overlay vs page. No pixels.
  3. Name the state (12-20). Entities, IDs, UI flags, derived values. One source of truth per fact.
  4. Walk data flow (20-32). One event: what writes, what is derived, what hits the network, what the next paint shows. Then one failure (empty, 500, abort, pause).
  5. Events and API (32-40). Public props and callbacks, key map for the primary widget, request shape. Still not CSS.
  6. Accessibility (40-45). Tab, arrows, Escape, focus move, accessible names. Native elements before roles.

If you are picking colors at minute 25, say so and go back to state.

Box the UI

Boxes answer “what is on screen,” not “how it is laid out.” A command palette is not a pretty modal. It is:

[App shell]
  [Trigger]
  [Palette]          (only when open)
    [Search input]
    [Result list]
      [Row]  (icon, title, shortcut)
    [Footer] (Enter / Esc hints)

Mark the scroll region. Mark overlay (palette, modal) versus inline (nested checkboxes, stopwatch). If two regions share data, draw an arrow after they have names.

Skip column counts, font sizes, and whether the overlay is position: fixed. Portal is one spoken sentence (“render into document.body so stacking is honest”), then move on.

Name the state

Three buckets. If a field can be computed from another, it is not stored.

Bucket Palette Stopwatch Nested checkboxes Modal
Truth open, query, selectedIndex, commands status, accumulatedMs, startedAt Set of leaf ids open, opener
Derived filtered, highlight elapsedMs at now parent checked / mixed rest of page inert
Do not store isEmpty boolean ticks++ indeterminate on every node isCentered

The stopwatch is the clean fake-model example. Do not increment a counter on an interval. Elapsed time is a function of clocks:

function elapsedMs(now, watch) {
  if (watch.status !== 'running') return watch.accumulatedMs;
  return watch.accumulatedMs + (now - watch.startedAt);
}

// pause: accumulatedMs = elapsedMs(now, watch); status = 'paused'
// start: startedAt = now; status = 'running'
// reset: accumulatedMs = 0; startedAt = null; status = 'idle'

Mixed checkboxes: mixed is derived from which leaves are in the set. Parent click writes leaves. Modal “centered” is CSS. Modal state is open plus where focus returns. Say who owns the write. Do not lift selectedIndex into a global store because you are nervous.

Walk the data flow

For one action (type in the palette, toggle a leaf):

  1. Name the event (input, click, ArrowDown, Escape).
  2. Name the state write.
  3. Name derived that changes.
  4. Name the network if any, and how a stale response dies (AbortController or a sequence number).
  5. Name the next render.
  6. Name the failure (no matches, 500, already paused, empty tree).

Talk in arrows:

Cmd-K → open true → focus input
input "nav" → query → filtered rows → selectedIndex = 0
ArrowDown → selectedIndex + 1 (clamp)
Enter → run command → open false → restore focus

The interviewer can attack any arrow. If you cannot walk it, the boxes were decoration.

What to put on the board vs what to skip

Put on the board Skip unless they ask
Region boxes and component names Pixel padding, color tokens, fonts
Truth vs derived vs “do not store” Redux vs Zustand vs context
One happy-path sequence Every product edge
One failure: empty, error, pause Retry copy
Endpoint, payload, error union Auth provider internals
Key map for the primary widget Full ARIA spec dump
Portal or native dialog as a note CSS centering puzzles
Stretch parking list File tree

CSS last means you may write list: overflow auto as a region constraint. You may not open a 12-column grid. If they insist on layout, spend two minutes on stacking (overlay on top, focus inside) and return to flow.

Accessibility in the last five minutes

Checklist, out loud, pointing at the boxes. You are not implementing a focus trap unless they converted the round into machine coding.

  1. Native first. Search is an <input>. Controls are <button type="button">. Modal prefers <dialog> and showModal() over a div plus ten ARIA attributes.
  2. Keyboard. Tab through the boxes you drew. Arrows for list rows and tree nodes. Escape closes overlays. Enter runs the highlighted command or toggles the focused checkbox.
  3. Focus. Open: move in. Close: restore to the stored opener. Do not leave focus on a node you are about to unmount.
  4. Names. Icon-only close needs an accessible name.
  5. What the screen reader already needs. Modal: labelled dialog, content behind inert. Nested checkboxes: mixed is DOM indeterminate (or aria-checked="mixed" on a custom control), not a second React boolean.

If time dies at minute 44, say the next three keys you would wire. Silence does not score. Broader language: accessibility talking points. Keyboard: MDN keyboard accessible.

Footguns

  • Starting with CSS or a library debate.
  • Storing derived flags (isEmpty, indeterminate, elapsedTicks) that fight the next event.
  • Walking the happy path only.
  • Designing auth, SSR, and cache. That is system design. Stay in the feature unless they zoom out.
  • Implementing a whole command palette on the board. Pseudocode one handler. Save shipping for machine coding.

Interview out-loud answer

“I would lock MVP, then draw boxes for the regions so every later field has a home. I would list state as source of truth versus derived, and refuse tick counters or mixed flags that can be computed. I would walk one event from the handler to the next render, then one failure. CSS stays last: overflow and overlay, not pixels. In the last five minutes I would name Tab, arrows, Escape, where focus moves, and the accessible name for icon buttons. Stretch stays on a parking list so we can extend if there is time.”

Further reading