Use Template

Opens this plan in Hirezen, where one click makes it a position.

Frontend Developer interview questionsComponent API review — a dialog for the design system round

A 60 min interview plan with a time-boxed script, what each question is for, and the signals to score against. Key skills: Reviewing a modal dialog before it joins a design system: open state copied from props, a backdrop that closes mid-selection, a button array that cannot show a busy confirm, where focus goes when the element that opened the dialog is gone, and writing an API that makes the accessible use the easy one..

The pull request

20 min
What this section is for

Purpose

Runs over a pull request you write beforehand against your design system and share at the start. Its description says the dialog is meant to replace the thirty hand-rolled modals in the product, and that two teams already build on the branch. `Dialog.tsx` is about 120 lines, with props `isOpen`, an optional `onClose`, an optional `title`, `children`, `footerButtons` as an array of `{ label, onClick, variant }`, `closeOnBackdropClick` defaulting to true, and `size`. Plant these: the component copies `isOpen` into its own state and mirrors it with an effect only when the prop changes, while Escape and the backdrop hide the dialog by setting that copy to false and then call `onClose` if one was passed; `title`, when given, renders as a plain `div`, and the panel has `role="dialog"` with no `aria-modal` and no `aria-labelledby`; focus moves to the panel on open, and nothing keeps Tab inside, makes the page behind inert, or returns focus on close; and the panel is rendered inside the backdrop element, whose `onClick` closes the dialog when `event.target === event.currentTarget`. Two call sites come with it. Account's edit-address form keeps the dialog mounted, drives `isOpen` from its own Edit, Save and Cancel buttons, passes no `onClose` and no `title`, and renders its own heading in `children`; its bug on the pull request says that after Escape the dialog will not open again until the page is reloaded, and that it sometimes closes while someone is selecting text. Billing's cancel-subscription confirmation mounts the dialog only while it is open and clears that flag in `onClose`; it passes `footerButtons={[]}` and renders its own buttons in `children`, because its confirm calls an API for about two seconds and the array cannot show a busy button. Billing's flow starts from a "More" menu on each row of a subscriptions table, and confirming removes the row. What is right: the portal to `document.body`, and the scroll lock, which restores the previous `overflow` value on close. The component is React; the review points hold in any component framework. Book 70 minutes so the candidate's questions do not eat into the 60.

I'm [YOUR_NAME], and I maintain the component library at [COMPANY_NAME]. This pull request adds a dialog. Two product teams are already using it from the branch, and one of them has filed a bug against it. You're the reviewer — ask me anything you would ask the author.

What this section is for

Purpose

Puts the candidate in a reviewer's seat with real consumers, so the review is about the people calling the component rather than how its code looks.

Review it as the owner of the design system. What has to change before it merges, what can wait for a follow-up, and what would you ask the author?

What this question is for, and what to listen for

Purpose

The load-bearing question. Two of the plants are visible only through the call sites, so the separator is whether the candidate reads the consumers as carefully as the component.

Signals to score

  • Finds the copied `isOpen` state, and uses the two call sites to explain why Account's dialog will not reopen after Escape while Billing's works
  • Gives open state one owner — the caller, through a value and a change callback that cannot be left out — with any uncontrolled default made explicit
  • Reads Billing's empty `footerButtons` and hand-drawn buttons as the configuration API failing its first real consumer
  • Traces the backdrop bug to where the click is dispatched: a press that starts in the form and ends over the backdrop fires the click on the backdrop, so the check passes
  • Flags that the dialog has no accessible name when `title` is left out, and that `title` is not connected to the dialog even when present
  • Flags that Tab leaves the dialog, the page behind stays interactive, and focus is not returned on close
  • Sorts the findings by what gets more expensive after merge — API shape before anything else — and says what that means for the two teams already on the branch
  • Says what is right — the portal, and the scroll lock that restores the previous value — so the review is not a rewrite
  • Asks about the consumers before the code: which flows each team built, and what they needed that the component did not give them

Follow-up questions

  • Account says that after Escape the dialog won't open again until they reload. Billing says it works. Who is right?
  • Billing passes an empty `footerButtons` and draws its own buttons. What is that telling you?
  • Someone selects text in the address field and lets go over the dark background. What happens, and why?
  • Which of your comments block the merge, and which get more expensive if they wait?
  • What would you ask the author before writing any of this down?

Where focus goes

18 min
What this section is for

Purpose

Walk Billing's flow with the candidate one keypress at a time. What separates candidates is the confirm: by the time the dialog closes, every element focus came from has been removed.

Let's follow a keyboard user through Billing's flow: the "More" menu on a row, "Cancel subscription", the dialog, Confirm, and the row disappearing.

What this section is for

Purpose

Fixes the flow before the question, so the answer comes as a sequence of focus positions rather than a list of rules.

Tell me where keyboard focus is at every step of that flow, what a screen reader user hears along the way, and what the component has to let Billing say about it.

What this question is for, and what to listen for

Purpose

Reads accessibility where it is hardest to fake: focus over time, across a flow that removes the elements focus came from. Saying "trap focus in the modal" is common; knowing what to do when there is nothing left to return focus to is not.

Signals to score

  • Walks the flow as focus positions: the "More" button, the menu item, the dialog, Confirm, the row removed
  • Puts initial focus somewhere deliberate — Cancel for a destructive confirmation, the first field for a form — and says why not the confirm button
  • Keeps Tab from reaching the page behind, naming the native `<dialog>` opened with `showModal()` or the `inert` attribute rather than a hand-written trap
  • Names the dialog by its heading and describes it by its consequence, so a screen reader user hears what they are confirming
  • Returns focus on Escape or Cancel to the row's "More" button, noticing that the element that actually opened the dialog — the menu item — no longer exists once the menu closes
  • On confirm, recognises that the "More" button goes with the row, and chooses where focus lands instead of letting it fall to the page
  • Tells a screen reader user the outcome — the subscription was cancelled — in a way that is not lost when focus moves
  • Turns the flow into API: the caller can say where focus goes on close, with a default of the element focused before opening when it is still in the page
  • Checks it with the keyboard alone, then with a named screen reader

Follow-up questions

  • The menu closed when "Cancel subscription" was chosen. Which element opened the dialog, and does it still exist?
  • Which button has focus when the dialog appears, and why that one?
  • The user presses Escape. Where does focus go?
  • The user confirms and the row disappears. Where does focus go now, and what does a screen reader user hear?
  • What does the component have to accept so Billing can get this right?

The API you would merge

22 min
What this section is for

Purpose

The candidate writes. Types in whatever notation they like, and both call sites rewritten with them; a description of the API without the call sites is not an answer yet.

Now design the one you would merge. Types first, then Account's and Billing's call sites rewritten with it.

What this section is for

Purpose

Makes the call sites the test of the API, which is how the teams using it will judge it.

Show me the API you would merge, as types, with both call sites rewritten. Then tell me how it replaces the thirty hand-rolled modals without a big-bang migration.

What this question is for, and what to listen for

Purpose

Moves from critique to design. The API is scored on whether it makes the wrong use hard — an unnamed dialog, two owners for open state, a busy confirm nobody can show — and on whether the candidate uses the two call sites as its test.

Signals to score

  • Writes the API as types before prose, and rewrites both call sites with it
  • Gives open state one owner — a value and a change callback — and says whether an uncontrolled default is offered and who it is for
  • Makes an accessible name hard to leave out — a required title part connected to the dialog, or a development warning when no name is present — and says why types alone cannot enforce it
  • Composes the dialog from parts — title, description, body, footer — instead of configuring buttons through an array
  • Lets Billing keep the dialog open with its buttons busy while the confirm runs, and show the error inside the dialog if it fails
  • Tells the caller why the dialog wants to close — Escape, backdrop or a close button — so Account can refuse while its form has unsaved changes
  • Makes initial focus and focus on close part of the API, with defaults that are right for most callers
  • Keeps styling hooks narrow — a size, a class on the panel — and says what they are refusing to expose
  • Plans the move from thirty hand-rolled modals without a big-bang: which go first, how the old ones are marked, and what would show it worked
  • Names the smallest version they would merge this week

Follow-up questions

  • Show me Account's call site with your API. What did it lose, and what did it gain?
  • Billing's confirm takes two seconds and sometimes fails. Walk me through that with your API.
  • Under your design, how does someone ship a dialog with no name?
  • Account's form has unsaved changes and the user presses Escape. Who decides what happens?
  • Thirty hand-rolled modals exist today. Which do you move first, and how do you know the migration is working?

That's the review. What would you like to ask about how the design system works here? [Name one thing a contributor meets in their first month: a component with a known accessibility bug, a prop everyone misuses, a migration that stalled.]

What this section is for

Purpose

Candidates who have maintained shared components ask how changes reach the teams using them and who decides; others ask about the styling approach. The bracketed fact should be one you would tell a new hire anyway.

Frontend Developer interviews — common questions

Who is this Frontend Developer interview plan for?
It is written for the interviewer, not the candidate: the hiring manager, engineer or panel member running the Component API review — a dialog for the design system round for a Frontend Developer role. It gives you a 60 min script to follow in the conversation — 3 questions with what each one is for and the signals to score against — so you are not writing the round from scratch the night before.
What does the Component API review — a dialog for the design system round assess?
This round is focused on: Reviewing a modal dialog before it joins a design system: open state copied from props, a backdrop that closes mid-selection, a button array that cannot show a busy confirm, where focus goes when the element that opened the dialog is gone, and writing an API that makes the accessible use the easy one.. It works through The pull request, Where focus goes and The API you would merge, scoring against 28 observable signals, with follow-up prompts on all 3 questions for going deeper where an answer is thin.
How is the 60 min split up?
The pull request (20 min), Where focus goes (18 min), The API you would merge (22 min). The timings are there so the round stays on schedule and every candidate gets the same shape of interview — which is what makes two candidates comparable afterwards.
What other rounds should I run for a Frontend Developer?

A single round does not cover a whole role. The other rounds in this library for a Frontend Developer: