Opens this plan in Hirezen, where one click makes it a position.
Frontend Developer interview questionsCore Web Vitals review — fast in the lab, slow on phones round
A 60 min interview plan with a time-boxed script, what each question is for, and the signals to score against. Key skills: Reading Core Web Vitals from field data and a trace rather than a Lighthouse score: why a category page that scores 98 in the lab responds slowly on phones, where 410 ms of one filter click goes and what each fix is worth, and what virtualising the product grid would cost keyboard and screen reader users..
Which numbers to believe
What this section is for
Purpose
Runs over a performance pack for one category page of an online shop, sent the day before. Compose it so every number agrees with every other. Field data from the Chrome UX Report, the 28 days to yesterday, at the 75th percentile: on phones LCP 2.3 s, INP 350 ms, CLS 0.04; on desktop LCP 1.6 s, INP 110 ms, CLS 0.03. The team's own real-user monitoring, collected with the web-vitals library's attribution build: p75 INP on phones was 160 ms in the four weeks before the "instant filters" release, which moved filtering from a page reload to the client, and 410 ms in the three weeks since — so the CrUX window still holds one week from before. Of phone interactions slower than 200 ms since the release, 71% have a filter checkbox as their target and 94% of those happen after the page has finished loading; a typical one is 20 ms of input delay, 330 ms of processing and 60 ms of presentation delay. A Lighthouse report a developer ran on a laptop with the desktop preset: score 98, LCP 0.9 s, TBT 30 ms, CLS 0, and two opportunities — reduce unused JavaScript by 190 KB, and properly size images to save 310 KB. Both opportunities are real and neither is the problem. Last, a Performance panel recording of one click on the "In stock" filter on a mid-range Android phone: 410 ms end to end, made of 20 ms input delay, 330 ms processing and 60 ms presentation delay. Record it yourself from a branch with these defects: the category holds 1,200 products in a CSS Grid and every one is rendered, with 1,130 still showing after the click; every card re-renders, and the grid passes each card a new inline `onAddToCart` function; `formatPrice` constructs a new `Intl.NumberFormat` on every call, and the bottom-up view puts 95 ms on the constructor; a `useEqualRowHeights` layout effect, left over from before the listing used CSS Grid, reads each card's height and writes a style in the same loop, 70 ms flagged as forced reflow; card rendering totals 230 ms including the formatter, and the handler, URL update and filter function take 30 ms together. If your recording comes out differently, change the pack until every number agrees with it. The branch is React; in another framework, plant the same three causes — every card re-rendered, a formatter built per card, a height loop that reads and writes in turn. Keep a second item back for the third section. Book 70 minutes; the candidate's questions sit outside the 60.
I'm [YOUR_NAME], and I look after storefront performance at [COMPANY_NAME]. You've had the pack since yesterday, so I won't ask what any of the acronyms stand for. I want to know what's slow, for whom, and what you'd do about it first.
What this section is for
Purpose
Takes definitions off the table, so the hour goes on reading the data rather than reciting thresholds.
The lab report says 98. The field data says phones are slow. Which numbers do you believe, what exactly is slow and for whom — and what in this pack would you deliberately not work on?
What this question is for, and what to listen for
Purpose
Reads whether the candidate knows what each source can and cannot see. The lab and the field disagree here for ordinary reasons, and the attribution data does most of the diagnosis before anyone opens the recording.
Signals to score
- Trusts the field data for this question, and says why one desktop-preset run on a laptop cannot show it
- Notices the lab report has no INP at all, because a navigation run never clicks anything, and that TBT describes loading
- Reads each field metric against its threshold at p75: on phones LCP and CLS pass and INP does not, and desktop passes all three
- Ties the jump to the "instant filters" release using the team's own monitoring, and knows CrUX is a rolling 28-day window that lags the release and will lag a fix
- Uses the attribution data: most slow interactions are filter clicks, after the page has loaded, and processing is most of their time
- Concludes from the 20 ms input delay and the load state that the unused-JavaScript opportunity is not this problem
- Leaves the image and bundle opportunities for later while saying they are real
- Says who the problem belongs to in product terms — shoppers on phones using filters — rather than "the score"
- Asks how much of the shop's phone traffic uses filters before calling it urgent
Follow-up questions
- Lighthouse says 98. Why doesn't that settle it?
- Where in this pack is INP measured, and where is it not?
- Your own monitoring says 410 ms since the release. Why does CrUX say 350?
- Before the release a filter reloaded the page. Was the old flow faster?
- Lighthouse wants 190 KB of unused JavaScript removed. Will that fix the filters?
One click, 410 milliseconds
What this section is for
Purpose
The candidate opens the recording — the trace file in DevTools if you can share it, screenshots of the flame chart and the bottom-up table if not — and drives. The three causes in it are of three different kinds; the order the candidate takes them in, and the saving they claim for each, are what get scored.
Open the recording of the "In stock" click and take me through it.
What this section is for
Purpose
Moves from percentiles to one interaction, which is where any change has to come from.
Take me through where the 410 ms go, and tell me what you would change — in what order, and what each change should buy.
What this question is for, and what to listen for
Purpose
The load-bearing question of the round. Anyone can list performance techniques; the separator is whether each proposed change is tied to a line in this recording and to the phase of the interaction it shortens.
Signals to score
- Splits the 410 ms into input delay, processing and presentation delay, and says which phase each cause sits in
- Finds the `Intl.NumberFormat` constructor in the bottom-up view and builds the formatter once per locale and currency instead of once per card per render
- Recognises `useEqualRowHeights` as a loop that alternates reads and writes and forces a layout each time, and replaces it with CSS rather than only batching the reads
- Questions whether 1,200 products belong in one grid on a phone, and takes a page size to whoever owns the listing as a product decision
- Lets the checkbox paint before the grid updates — a transition or a deferred value in React, yielding to the main thread outside it — and knows INP ends at the next paint
- Knows that yielding does not remove work: a long commit still blocks, and a tap that lands during it still waits
- Checks whether memoising the cards would skip anything, and notices that the inline `onAddToCart` hands every card a new prop on every render
- Puts an expected saving beside each change, and re-records after each one rather than shipping them together
- Says how the fix will be confirmed for shoppers — the team's own monitoring of phone filter clicks, day by day — without waiting for CrUX
Follow-up questions
- Which phase of the interaction does each of the three causes land in?
- The constructor takes 95 ms across 1,130 cards. What's the change, and what should it save?
- What is `useEqualRowHeights` for, and does it need JavaScript?
- You wrapped the grid update in a transition and INP dropped to 90 ms. Is the page faster?
- How will you know next week whether shoppers got the improvement?
The fix that hides the cards
What this section is for
Purpose
Hand over the second item only now: a pull request from a colleague that virtualises the grid with a windowing library, so only the two dozen cards nearest the viewport are mounted, with a recording from that branch showing the same click at 120 ms. It changes nothing else. This section is the round's accessibility read, and it is framed as a performance win on purpose.
A colleague has already opened a pull request for this. Their recording shows the same click at 120 ms.
What this section is for
Purpose
Presents the change as finished and measured, so objecting to it is a choice the candidate has to make unprompted.
Would you approve it? Tell me who it breaks things for, and what you would do instead or as well.
What this question is for, and what to listen for
Purpose
Reads accessibility against a real trade. A candidate who knows what windowing removes — from find-in-page, from a screen reader's path through the grid, from focus — weighs it against the win; one who does not approves the number.
Signals to score
- Says that virtualising removes off-screen products from the DOM, and with them from the accessibility tree and from find-in-page
- Describes what a screen reader user moving through the grid meets: a list that ends after the rendered cards with no sign that more follow
- Finds the focus failure: a focused card scrolled out of the window is unmounted, and focus falls back to the document
- Asks whether the formatter, the layout effect and a page size bring the click under 200 ms without making any product unreachable, and wants that measured first
- Proposes `content-visibility: auto` with an intrinsic size, and says it saves style, layout and paint for off-screen cards but not the JavaScript render
- Proposes a page size with a "Show more" button, and says where focus goes when the next products are added
- If windowing ships anyway, requires each item to expose its position and the set size, focus kept on an item that scrolls away, and a way to reach the end
- Checks the change with a screen reader and with find-in-page before approving, not only with a recording
- Weighs the two costs out loud rather than treating accessibility as a veto or as an afterthought
Follow-up questions
- Search the page for the name of a lamp near the bottom of the category. What happens?
- A screen reader user moves through the grid one product at a time. Where does it end?
- Someone tabs to "Add to cart" on a card, then scrolls down with the arrow keys. Where is focus a moment later?
- What does `content-visibility: auto` save here, and what does it not?
- If this had to ship with windowing, what would you require of it first?
That's all I wanted to ask. Your turn — anything about how performance is looked after here. [Be ready to say who owns the field numbers, how a regression gets noticed, and one slow thing you know about and have not fixed.]
What this section is for
Purpose
A candidate who has done this work asks who owns the numbers and what happens when they move; one who has not asks which tools the team uses. A real, unfixed problem in the answer tells the first kind what the job is.
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 Core Web Vitals review — fast in the lab, slow on phones 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 Core Web Vitals review — fast in the lab, slow on phones round assess?
- This round is focused on: Reading Core Web Vitals from field data and a trace rather than a Lighthouse score: why a category page that scores 98 in the lab responds slowly on phones, where 410 ms of one filter click goes and what each fix is worth, and what virtualising the product grid would cost keyboard and screen reader users.. It works through Which numbers to believe, One click, 410 milliseconds and The fix that hides the cards, scoring against 27 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?
- Which numbers to believe (16 min), One click, 410 milliseconds (24 min), The fix that hides the cards (20 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: