Interview Prep

The Frontend Engineering Interview

JavaScript · React · CSS · Performance · Accessibility

Frontend interviews are less standardised than backend ones — you might get algorithm problems, live coding on UI challenges, take-home projects, or deep dives into browser internals. This guide prepares you for all of it.

What the interview process looks like

1
Initial screen — 30 min
Background check + 1 JavaScript fundamentals question. Expect closures, async/await, or a simple DOM manipulation task.
2
Take-home challenge — 2–4 hours (sometimes)
Build a small app or component. Quality over completeness. Clean code, good state management, and some thought on edge cases impress more than adding features.
3
Technical deep-dive — 60–90 min
JavaScript fundamentals, framework-specific questions, CSS challenges, or a live coding task. Often extends into performance and accessibility for senior roles.
4
System / architecture design — 60 min (mid–senior)
Frontend-specific: "Design a component library" or "How would you architect a large-scale single-page application?" Different from backend system design but equally important.
5
Pair programming session (sometimes)
Debug or extend an existing codebase. Shows how you work in a real environment — reading unfamiliar code, asking questions, and not panicking.

JavaScript Fundamentals

Most frontend interview failures happen here. Candidates who only know React struggle when asked about JavaScript itself. Know the language, not just the framework.

Closures

A closure is a function that retains access to its outer scope even after the outer function has returned. This is one of the most common interview topics — not as a trivia question, but as a practical debugging and design concept.

  • Know how closures create data privacy (module pattern, factory functions)
  • The classic loop + closure bug: var in a loop with a timeout. Why it happens. How let fixes it. How an IIFE fixes it.
  • Closures in React: why stale closures happen in useEffect and how to avoid them

The Event Loop

Understanding the event loop is what separates developers who guess at async behaviour from those who reason about it.

  • Call stack → Web APIs → Callback queue → Event loop
  • Microtasks (Promises, queueMicrotask) run before macrotasks (setTimeout, setInterval)
  • Why Promise.resolve().then() runs before setTimeout(fn, 0)
  • How this affects rendering: the browser paints between tasks, not between microtasks

Async/Await & Promises

  • How Promises work under the hood — states: pending, fulfilled, rejected
  • async/await is syntactic sugar over Promises — know what the compiled code looks like
  • Error handling: try/catch with async/await vs .catch() on Promises
  • Promise.all vs Promise.allSettled vs Promise.race — know when to use each
  • Implement Promise.all from scratch — a classic interview task

this binding

  • Regular functions: this depends on how the function is called
  • Arrow functions: this is lexically bound — it takes this from the enclosing scope at definition time
  • call, apply, bind — when and why you'd use each
  • Class methods and losing this when passing them as callbacks

Essential array methods — implement from scratch

Interviewers often ask you to implement map, filter, or reduce to test whether you understand what they actually do.

  • Array.prototype.map — returns a new array, same length, each element transformed
  • Array.prototype.filter — returns a new array with only elements that pass the predicate
  • Array.prototype.reduce — accumulates a single value. The most powerful, the least understood.
  • debounce and throttle — implement both. Understand the difference: debounce delays until quiet, throttle limits frequency.

React

React interviews often focus less on "how do you use React" and more on "why does React work this way." Understanding the underlying model makes the tricky questions obvious.

Hooks in depth

  • useState — updates are asynchronous and batched in React 18. Never mutate state directly.
  • useEffect — runs after render. The dependency array controls when. An empty array means "on mount only." No array means "after every render."
  • useRef — persists a value across renders without triggering re-renders. Two use cases: DOM access and mutable values.
  • useMemo — memoises a computed value. Use when the computation is expensive. Don't use it by default — there's overhead.
  • useCallback — memoises a function reference. Useful when passing callbacks to child components that are wrapped in React.memo.
  • useContext — reads from context. Know its limitations: all consumers re-render when the context value changes.

Reconciliation & the Virtual DOM

  • React builds a Virtual DOM tree and diffs it against the previous tree on each render
  • The key prop tells React how to match old and new elements. Wrong or missing keys cause unnecessary re-mounts.
  • When a parent re-renders, all children re-render by default — unless wrapped in React.memo
  • React 18 concurrent features: startTransition, automatic batching — know what they solve, even if you haven't used them

State management patterns

  • Lifting state — move state to the nearest common ancestor of components that need it
  • Prop drilling — passing props through many layers. The smell that leads to context or a state library.
  • Context API — good for low-frequency updates (theme, auth user, language). Bad for high-frequency updates (every keystroke).
  • External state (Redux, Zustand, Jotai) — know the tradeoffs. Zustand is simple; Redux is verbose but predictable at scale.
  • Server state (React Query, SWR) — separate server-fetching concerns from UI state. Know why this matters.

CSS & Layout

CSS questions trip up many mid-level developers. It's often undertested in daily work, but interviewers use it to reveal gaps in foundational knowledge.

Core concepts

  • Box model — content → padding → border → margin. Know the difference between box-sizing: content-box and box-sizing: border-box. Use border-box and know why.
  • Specificity — calculated as (inline, IDs, classes/attributes, elements). Higher specificity wins regardless of source order. !important overrides all — treat it as a last resort.
  • Stacking contextz-index only works within the same stacking context. Elements with position, opacity < 1, or transform create new contexts.
  • BEM — Block, Element, Modifier. A naming convention that prevents specificity wars and makes component styles self-documenting.

Flexbox & Grid

  • Flexbox — one-dimensional layout. Know justify-content, align-items, flex-grow, flex-shrink, flex-basis. Understand the difference between main axis and cross axis.
  • CSS Grid — two-dimensional layout. grid-template-columns, grid-template-rows, grid-area. auto-fill vs auto-fit with minmax for responsive grids without media queries.
  • Know when to use Flexbox vs Grid: Flexbox for component-level layout, Grid for page-level layout.

Web Performance

Core Web Vitals

  • LCP (Largest Contentful Paint) — how fast the main content loads. Target: under 2.5s. Fix by optimising images, preloading key resources, eliminating render-blocking scripts.
  • INP (Interaction to Next Paint) — responsiveness. Fix by keeping the main thread unblocked — defer non-critical JS, use web workers for heavy computation.
  • CLS (Cumulative Layout Shift) — visual stability. Fix by giving images explicit dimensions, avoiding injecting content above existing content.

Practical optimisation techniques

  • Code splitting — split your bundle and load only what's needed for the current route. React.lazy + Suspense for component-level splitting.
  • Tree shaking — dead code elimination at build time. Requires ES modules (import/export, not require).
  • Image optimisation — modern formats (WebP, AVIF), responsive images with srcset, lazy loading with loading="lazy".
  • Debounce & throttle — prevent expensive handlers from firing too frequently (scroll, resize, input).
  • Memoisation — cache the results of expensive computations. In React: useMemo for values, useCallback for functions.

Accessibility

Accessibility is no longer a niche topic. It's asked at senior level interviews and is a strong differentiator. Most candidates know very little about it.

What to know

  • Semantic HTML first — use <button>, <nav>, <main>, <article>. ARIA is for when semantic HTML isn't enough — not as a replacement.
  • ARIA roles & attributesaria-label, aria-expanded, aria-live, aria-hidden. Know when each is needed.
  • Keyboard navigation — every interactive element must be reachable and operable with a keyboard. Focus order must make logical sense.
  • Focus management in SPAs — when navigating between routes, move focus to the new page heading. When opening modals, trap focus inside. When closing, return focus to the trigger.
  • Colour contrast — WCAG AA requires 4.5:1 for normal text. Know how to check it (browser DevTools, axe extension).

Common questions

Explain event delegation and why it's useful.
Events bubble up the DOM. One listener on the parent handles clicks on all children. Efficient for dynamic lists.
What's the difference between == and ===?
== coerces types; === checks type and value. Know the coercion rules — they come up in follow-up questions.
Implement debounce(fn, delay).
Classic. Use a closure to hold the timer. Clear it on each call. Fire fn after the timer expires.
Why might a React component re-render unexpectedly, and how would you fix it?
New object/array references as props, parent re-renders, context changes. Fix with React.memo, useMemo, useCallback.
How would you design a component library for a large team?
Design tokens, atomic design, Storybook, versioning strategy, accessibility-first, TypeScript for contracts.
What happens between typing a URL and the page appearing on screen?
DNS lookup → TCP handshake → TLS → HTTP request → HTML parse → render pipeline. Go as deep as you can.
How do you optimise a React app that feels slow?
Profile first (React DevTools). Look for unnecessary re-renders, large bundle, blocking the main thread. Fix the actual bottleneck, not the imagined one.

Tips from the hiring side

What separates strong frontend candidates
  • They understand the browser, not just the framework. When the framework fails, they don't panic.
  • They talk about performance with real numbers, not just "I made it faster." Know Lighthouse, Core Web Vitals, and what moves them.
  • They build things. Reading about closures is not the same as debugging a stale closure in a real codebase.
  • For take-homes: readme matters. Explain what you built, what you'd do with more time, and any tradeoffs you made.
  • CSS knowledge is a genuine differentiator. Most candidates handwave it. Those who know it well stand out immediately.
  • Don't just know React — know why React makes the design choices it does. That's what senior engineers show in interviews.