Interview questions

Mid-Level Frontend Engineer Interview Questions

Mid-level frontend interviews test whether you can move beyond syntax knowledge into genuine understanding of browser mechanics, component architecture, and performance tradeoffs. Interviewers are checking if you can own a feature end-to-end, make defensible technical decisions, and communicate clearly with teammates — not just whether you can code.

What to expect

A typical mid-level frontend loop runs 4–5 rounds: one or two coding rounds (DOM manipulation, array/string problems, or small UI component implementation in vanilla JS or your framework of choice), one system design or UI architecture round focused on component design or state management rather than distributed systems, one behavioral round, and sometimes a take-home or live CSS/layout challenge. You won't be expected to design Kafka pipelines, but you will be expected to reason about rendering performance, network waterfalls, and accessibility without being prompted.

These are the questions every Frontend Engineer gets.

Get questions tailored to your experience, answer them, and get honest feedback — free, no credit card.

Run a free fit check →

12 questions, with how to answer them

  1. JavaScript Fundamentals

    1. Explain the event loop and how it relates to microtasks and macrotasks. Given a mixed block of setTimeout, Promise.then, and synchronous code, walk through the exact execution order.

    How to answer: Start with the call stack, then describe the task queue (macrotasks: setTimeout, setInterval, I/O) versus the microtask queue (Promise callbacks, queueMicrotask, MutationObserver). The key rule: after each macrotask, the engine drains the entire microtask queue before pulling the next macrotask. Walk through a concrete example step-by-step, annotating what goes where and in what order.

    What they look for: Interviewers want to see that you actually understand async execution rather than having memorized 'Promises are faster than setTimeout.' Can you predict real-world race conditions? Do you know that microtasks can starve the rendering pipeline if you're not careful?

  2. JavaScript Fundamentals

    2. What is a closure, and give a concrete real-world example where misunderstanding closures causes a bug — then fix it.

    How to answer: Define closure as a function retaining a reference to its lexical scope even after the outer function has returned. For the bug, use the classic loop+setTimeout example with var (all callbacks close over the same binding). Show two fixes: replace var with let (block-scoped per iteration) or use an IIFE to capture the value. Explain why each fix works at the binding level.

    What they look for: The interviewer is checking whether you understand lexical scoping vs. dynamic binding, and whether you can connect a language mechanic to a real debugging scenario. Generic definitions without the bug example are a red flag at this level.

  3. CSS & Layout

    3. A flex container has three children. The middle child should grow to fill remaining space while the other two stay at their intrinsic size. Suddenly the layout breaks on Safari. Walk through how you'd diagnose and fix it.

    How to answer: Implement with flex-grow: 1 on the middle child and flex-grow: 0 (or no flex property) on the others. For the Safari diagnosis: check flex-basis — Safari historically required explicit flex-basis: 0 or flex-basis: auto depending on context. Mention using DevTools flex inspector, checking -webkit- prefixes, and testing with a minimal repro. Also address min-width: 0 as a common fix when a flex child overflows unexpectedly.

    What they look for: Can you handle real cross-browser layout bugs, not just write textbook Flexbox? The min-width: 0 insight and flex-basis nuance are strong positive signals. Interviewers want to see a structured debugging process, not guessing.

  4. React / Component Architecture

    4. You have a large list component that re-renders on every parent state change, causing visible lag. Walk through how you'd diagnose and fix the performance issue without reaching for a library.

    How to answer: Start with the React DevTools Profiler to confirm unnecessary re-renders. Then reason through the cause: is the parent passing a new object/array reference each render, or an inline callback? Solutions in order of invasiveness: (1) React.memo on the list component, (2) useMemo for derived data passed as props, (3) useCallback for handlers, (4) ensure stable key props. Also consider lifting state down or splitting context to reduce scope. Explain the tradeoffs of memoization — it costs memory and adds complexity, so measure first.

    What they look for: Interviewers want to see a diagnostic-first approach, not 'slap React.memo everywhere.' Do you understand referential equality in JS and how it interacts with React's reconciler? Do you know when memoization is not the right answer?

  5. React / Component Architecture

    5. Design a reusable, accessible Modal component in React. Walk through the API design, state management, focus trapping, and keyboard interaction.

    How to answer: API: accept isOpen, onClose, and children as minimum props; consider a title prop for aria-labelledby. Implementation: use a portal (ReactDOM.createPortal) to render outside the DOM hierarchy. Accessibility: set role='dialog', aria-modal='true', aria-labelledby. Focus trap: on open, move focus to the first focusable element; intercept Tab/Shift+Tab to cycle within the modal; restore focus to the trigger on close. Listen for Escape key to call onClose. Lock body scroll while open.

    What they look for: At mid-level, you're expected to design components that are actually production-ready. Accessibility is not a bonus — omitting focus trapping or aria attributes is a concrete failure signal. The portal choice shows understanding of z-index and DOM structure issues.

  6. State Management

    6. When would you choose React Context over a library like Zustand or Redux Toolkit, and what are the performance implications of each?

    How to answer: Context is appropriate for low-frequency updates like theme, locale, or auth status — its downside is that every consumer re-renders on any value change. For high-frequency or complex state (shopping cart, real-time data), a dedicated store is better because it allows selective subscription. Zustand is lightweight with selector-based subscriptions. Redux Toolkit adds structure, devtools, and middleware — worth it for large teams or complex async flows. Mention that Context + useMemo is sometimes enough but is easy to get wrong.

    What they look for: Interviewers want to see that you understand Context's re-render behavior and can make a principled tradeoff decision. 'It depends' is fine if you articulate what it depends on with specifics, not vague hand-waving.

  7. Browser & Performance

    7. A page scores poorly on Largest Contentful Paint (LCP). Walk through the top causes and a systematic remediation plan.

    How to answer: LCP measures when the largest above-the-fold element (image, heading, or block) is rendered. Common culprits: (1) unoptimized hero image — fix with modern formats (WebP/AVIF), correct sizing, and fetchpriority='high'; (2) render-blocking CSS or JS — defer non-critical JS, inline critical CSS; (3) slow server response (TTFB) — CDN, caching, or SSR/SSG; (4) lazy-loading the LCP element by mistake — never lazy-load it. Use Lighthouse and CrUX data to confirm field vs. lab results.

    What they look for: The interviewer is checking whether you know Core Web Vitals beyond their names and can connect specific optimizations to specific causes. Mentioning fetchpriority and distinguishing lab vs. field data are strong signals at this level.

  8. Browser & Performance

    8. Explain how the browser renders a webpage from HTML bytes to pixels. Where in this pipeline do layout thrashing and paint storms occur, and how do you avoid them?

    How to answer: The pipeline: Bytes → Characters → Tokens → DOM/CSSOM → Render Tree → Layout → Paint → Composite. Layout thrashing happens when JS reads a layout property (offsetWidth, getBoundingClientRect) immediately after writing a style, forcing the browser to recalculate layout synchronously (forced reflow). Batch reads before writes or use requestAnimationFrame. Paint storms occur when non-composited properties (width, margin, box-shadow) change frequently — prefer animating transform and opacity which run on the compositor thread.

    What they look for: This question separates engineers who have actually debugged jank from those who have only read about it. The detail about which CSS properties trigger layout vs. paint vs. composite is the key signal.

  9. Networking & APIs

    9. You need to fetch a list of users and then fetch each user's profile details in parallel. Write the implementation and explain the error-handling strategy.

    How to answer: Use Promise.all with users.map(user => fetch(user.detailUrl).then(r => r.json())) for parallel requests. Discuss the tradeoff: Promise.all rejects fast if any request fails. If partial data is acceptable, use Promise.allSettled and filter fulfilled results. Add explicit error handling for non-OK HTTP responses (fetch doesn't throw on 4xx/5xx — check response.ok). Consider a timeout wrapper using Promise.race with an AbortController. For very large lists, consider batching with concurrency limits.

    What they look for: The non-obvious insight that fetch doesn't reject on HTTP errors is a concrete signal. Understanding when to choose allSettled vs. all, and knowing how to implement a concurrency limit without a library, separates mid from junior.

  10. Testing

    10. You're asked to add tests to a React component that fetches data and renders a list. What do you test, and what do you deliberately NOT test?

    How to answer: Use React Testing Library with MSW (Mock Service Worker) to intercept network requests at the network level rather than mocking fetch directly. Test: (1) loading state appears initially, (2) list renders correctly on success, (3) error message renders on failure, (4) accessibility — list items have correct roles. Do NOT test: implementation details like state variable names, the specific HTTP library used, or internal component structure. Do not snapshot-test dynamic content — it creates fragile tests that break on every cosmetic change.

    What they look for: Interviewers want to see RTL's philosophy internalized: test behavior, not implementation. Mentioning MSW over jest.spyOn(global, 'fetch') is a strong signal. Knowing what NOT to test is as important as knowing what to test.

  11. Behavioral

    11. Tell me about a time you disagreed with a technical decision made by a senior engineer or tech lead. What did you do?

    How to answer: Use STAR but keep it technical. Describe the specific decision (e.g., a state management choice, an API contract, a CSS architecture approach), your technical reasoning for disagreeing, how you raised it (async RFC, synchronous conversation, PR comment), and the outcome — whether you changed their mind or agreed to disagree. Be honest if you were wrong in hindsight. Avoid making the other person sound incompetent.

    What they look for: Interviewers are assessing psychological safety and communication maturity. Can you advocate for a technical position without being combative? At mid-level, they want to see that you engage with technical decisions rather than silently accepting everything or escalating every disagreement.

  12. Behavioral

    12. Describe a feature you built end-to-end. What would you do differently now?

    How to answer: Pick a real, reasonably scoped feature. Walk through the decisions: how you broke down the work, what technical choices you made (component structure, data fetching strategy, error handling), how you handled edge cases, how you tested it. For the 'differently' part, be genuinely self-critical — maybe you over-engineered state management, skipped accessibility, or didn't account for an empty state. Vague regrets ('I'd test more') are weak; specific technical regrets are strong.

    What they look for: This question tests ownership, reflection, and technical judgment. Interviewers want to see that you can articulate not just what you built but why, and that you have enough perspective to identify your own tradeoffs. Engineers who can't find anything they'd change are a yellow flag.

Study tips

  • Practice the browser rendering pipeline until you can draw it from memory — layout, paint, and composite are terms you'll need to use correctly under pressure, not just recite.
  • Build a small project using only the Web Platform (no framework) to force yourself to understand what React, Vue, or Svelte are actually abstracting. DOM event delegation and manual diffing will surface gaps in your mental model.
  • Read the WAI-ARIA Authoring Practices Guide for at least modal, listbox, and combobox patterns — accessibility questions at this level expect concrete implementation knowledge, not just awareness that it matters.
  • For behavioral questions, prepare 4–5 solid stories and practice mapping them to different questions, rather than memorizing 10 separate stories. A good story about a difficult tradeoff can answer questions about conflict, failure, ownership, and collaboration.
  • In coding rounds, narrate your performance reasoning out loud before writing code — saying 'I'll use a Map here to get O(1) lookup instead of nested loops' signals the right instincts even if your syntax isn't perfect.

Practice these against your own résumé

Get questions tailored to your experience, answer them, and get honest feedback — free, no credit card.

Run a free fit check →