Skip to content

Frontend Development Interview Questions for 7 Years Experience

40 questions with answers for candidates with 7 years of experience — 18 medium, 22 hard.

What interviewers expect: 7 years experience

Seven-year candidates are evaluated as staff or lead engineers. Expect discussions on multi-team frontend platforms, micro-frontends versus monorepos, long-term technology strategy, engineering standards, and measuring impact through metrics. You should show examples of driving cross-team initiatives such as performance programmes or TypeScript migrations.

This set is weighted towards Web Performance (8), Frontend Architecture (7), Frontend Testing (6), Build Tools and Tooling (5).

Platform strategy Cross-team initiatives Engineering standards Impact measurement
Solved at this levelStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

After a release, the app shows a blank page in some older browsers. What could be wrong?

Save to ▾
Show answer
The build probably targets newer syntax or uses an API that older browsers lack, causing a parse error that stops the whole bundle. I would check the console in that browser, compare the build target and browserslist with our support policy, and add missing polyfills for used APIs. Error monitoring with browser breakdowns catches this quickly, and testing on the oldest supported browser should be part of release checks.
02

Mock fetch in a Vitest test to check error handling.

Save to ▾
Show answer
Stub the global fetch and assert behaviour: import { it, expect, vi, afterEach } from 'vitest'; import { loadCourses } from './api'; afterEach(() => vi.unstubAllGlobals()); it('returns an empty list when the server fails', async () => { vi.stubGlobal('fetch', vi.fn().mockResolvedValue( new Response('Server error', { status: 500 }) )); const result = await loadCourses(); expect(result).toEqual([]); expect(fetch).toHaveBeenCalledWith('/api/courses'); }); For larger suites, MSW handlers are cleaner than stubbing fetch in every test.
03

How would you choose a frontend framework for a new project?

Save to ▾
Show answer
I would base it on project needs and team context rather than trends: team experience, hiring market in India, SEO and rendering requirements, ecosystem maturity, long-term support and performance on target devices. React has the largest ecosystem and talent pool, Angular suits large enterprise teams wanting an opinionated structure, Vue is approachable, and Svelte or Astro produce less JavaScript. A small proof of concept helps confirm the choice.
04

What does structural typing mean in TypeScript?

Save to ▾
Show answer
TypeScript compares types by their shape, not by their declared names. If an object has all the properties a type requires, it is compatible, even if it was never declared as that type. This is flexible but can let a UserId string be passed where an OrderId string is expected. Teams use branded types, such as string & { __brand: 'UserId' }, to simulate nominal typing for important identifiers.
05

When should you mock in frontend tests, and what is Mock Service Worker?

Save to ▾
Show answer
Mock things that are slow, nondeterministic or outside your control, such as network calls, timers and browser APIs, but avoid mocking your own modules heavily, which makes tests pass while the real integration breaks. Mock Service Worker intercepts requests at the network level in both browser and Node, so your real fetch code runs against defined handlers. The same handlers can power tests, Storybook and local development.
06

Your page embeds a payment iframe from another domain and needs its result. How do you do it safely?

Save to ▾
Show answer
The iframe should send the result with parent.postMessage(data, 'https://yourshop.com'), and the page listens for message events, checking event.origin against the exact payment domain and validating the data shape before acting. The frontend message should only update UI; the final payment status must be confirmed from your server through the gateway's webhook or verification API, since messages can be spoofed.
07

TypeScript types say a field exists, but the app crashes because the API did not send it. How do you prevent this?

Save to ▾
Show answer
TypeScript only checks at compile time; it cannot guarantee what a server returns at runtime. I would validate responses at the boundary with a schema library like Zod or Valibot, deriving TypeScript types from the schema so they never drift. Invalid data then fails clearly with a logged error and a fallback UI. Generating types from OpenAPI specs also keeps frontend and backend contracts aligned.
08

Several teams contribute CSS to one large app and styles keep breaking each other. What do you propose?

Save to ▾
Show answer
I would introduce scoping so styles cannot leak, using CSS Modules or a consistent naming convention per team, and organise global styles with cascade layers for reset, tokens, components and utilities. A shared design token set and component library reduces one-off styles. Linting with Stylelint, visual regression tests in CI and clear ownership of global files prevent new conflicts.
09

What are long tasks and why do they hurt user experience?

Save to ▾
Show answer
A long task is any main-thread work lasting more than 50 milliseconds. While it runs, the browser cannot respond to taps or paint updates, so the page feels frozen. Common sources are large script evaluation, heavy JSON processing, big framework re-renders and third-party scripts. The Performance panel highlights them with red corners, and splitting work into smaller chunks or moving it to a worker keeps the page responsive.
10

Design the frontend for a search box with autocomplete suggestions.

Save to ▾
Show answer
I would debounce input by about 200 milliseconds, cancel outdated requests with AbortController and cache recent queries in a Map. Suggestions render in an accessible combobox pattern with aria-expanded, aria-activedescendant and arrow key navigation. I would highlight matched text safely, show loading and empty states, and limit results to around eight. Measuring latency and prefetching popular terms keep it feeling instant on slow networks.
11

What is visual regression testing?

Save to ▾
Show answer
Visual regression testing captures screenshots of pages or components and compares them pixel by pixel with approved baselines, flagging unexpected visual changes such as broken spacing or wrong colours. Tools include Playwright's toHaveScreenshot, Chromatic with Storybook and Percy. To avoid false failures, run in consistent containers, disable animations, and mask dynamic content like dates. It catches CSS bugs that functional tests miss.
12

Write a card that changes layout based on its container width.

Save to ▾
Show answer
Use a container query so the card adapts wherever it is placed: .card-wrapper { container-type: inline-size; } .card { display: grid; gap: 1rem; } @container (min-width: 420px) { .card { grid-template-columns: 160px 1fr; align-items: center; } } In a narrow sidebar the image stacks above text; in a wide main column it sits beside the text, with no viewport media queries.
13

Describe a disagreement with your team about choosing a tool or framework.

Save to ▾
Show answer
Situation: half the team wanted a heavy state management library for a new app, while I felt it was unnecessary. Task: we needed a decision quickly. Action: I suggested building the same feature both ways in a time-boxed spike and compared code size, learning curve and bundle impact. Result: the data favoured the simpler approach, the team agreed, and we documented criteria for when to add the library later.
14

How do monorepo tools like Turborepo or Nx help frontend teams?

Save to ▾
Show answer
A monorepo holds multiple apps and shared packages, such as a design system and utilities, in one repository using package manager workspaces. Turborepo and Nx add a task graph that understands dependencies between packages, run builds and tests only for affected packages, and cache outputs locally and remotely. This keeps CI fast as the repo grows and makes cross-package changes atomic in one pull request.
15

What are WeakMap and WeakRef, and when are they useful?

Save to ▾
Show answer
A WeakMap holds object keys weakly, so when no other reference to the key exists, the entry can be garbage collected. This makes it ideal for attaching private metadata or caching computed data for DOM nodes without causing memory leaks. WeakMap keys are not enumerable. WeakRef holds a weak reference to a single object and is rarely needed, mostly for caches, because garbage collection timing is unpredictable.
16

What are Web Components and Shadow DOM?

Save to ▾
Show answer
Web Components are native, framework-independent reusable elements built from Custom Elements, Shadow DOM and HTML templates. Shadow DOM attaches an encapsulated DOM tree to an element, so its styles do not leak out and page styles do not leak in, except through CSS custom properties and ::part. They are used for design systems shared across React, Angular and plain HTML apps. Server rendering and form participation need extra work.
17

Define brand design tokens in Tailwind CSS v4.

Save to ▾
Show answer
Tokens go in CSS with the @theme directive: @import 'tailwindcss'; @theme { --color-brand-500: #2563eb; --color-brand-700: #1d4ed8; --font-display: 'Poppins', sans-serif; --radius-card: 12px; } /* usage in markup */ /* <button class='bg-brand-500 hover:bg-brand-700 rounded-card font-display'> */ Tailwind generates utilities like bg-brand-500 from these variables and also exposes them as CSS custom properties for use in plain CSS.
18

Type checking takes several minutes in a large monorepo. How do you speed it up?

Save to ▾
Show answer
I would enable project references with composite builds so only changed packages are rechecked, and turn on incremental with build info files cached in CI. skipLibCheck avoids rechecking node_modules declarations. Very complex conditional types and huge unions slow the checker, so I would profile with --generateTrace and simplify hotspots. The bundler can use fast transpilation while type checking runs separately in parallel.
19

Collect Core Web Vitals from real users with the web-vitals library.

Save to ▾
Show answer
Report metrics to your analytics endpoint: import { onLCP, onINP, onCLS } from 'web-vitals'; function send(metric) { const body = JSON.stringify({ name: metric.name, value: metric.value, rating: metric.rating, page: location.pathname }); navigator.sendBeacon('/analytics/vitals', body); } onLCP(send); onINP(send); onCLS(send); sendBeacon delivers data reliably even when the page is closing. Aggregate at the 75th percentile per page.
20

Detect offline status and retry queued requests when the connection returns.

Save to ▾
Show answer
Listen for online and offline events and keep a small queue: const queue = []; async function send(req) { if (!navigator.onLine) { queue.push(req); showBanner('You are offline'); return; } await fetch(req.url, req.options); } window.addEventListener('online', async () => { hideBanner(); while (queue.length) await send(queue.shift()); }); window.addEventListener('offline', () => showBanner('You are offline')); navigator.onLine can report true on captive networks, so treat failed fetches as offline too. Persist the queue in IndexedDB for reliability.
21

Break a long-running loop into smaller tasks to keep the page responsive.

Save to ▾
Show answer
Yield to the main thread between chunks: function yieldToMain() { if (globalThis.scheduler?.yield) return scheduler.yield(); return new Promise(resolve => setTimeout(resolve, 0)); } async function processRows(rows) { let last = performance.now(); for (const row of rows) { processRow(row); if (performance.now() - last > 40) { await yieldToMain(); last = performance.now(); } } } The browser can handle clicks between chunks, which improves INP. scheduler.yield keeps the task's priority after resuming.
22

Write a React custom hook that fetches data and cancels on unmount.

Save to ▾
Show answer
Use AbortController inside useEffect: import { useEffect, useState } from 'react'; export function useFetch(url) { const [state, setState] = useState({ data: null, error: null, loading: true }); useEffect(() => { const controller = new AbortController(); setState(s => ({ ...s, loading: true })); fetch(url, { signal: controller.signal }) .then(r => (r.ok ? r.json() : Promise.reject(new Error(r.status)))) .then(data => setState({ data, error: null, loading: false })) .catch(err => { if (err.name !== 'AbortError') setState({ data: null, error: err, loading: false }); }); return () => controller.abort(); }, [url]); return state; } In production apps, TanStack Query adds caching and retries.
23

Most of your users are on low-end Android phones with slow networks. How does that change your approach?

Save to ▾
Show answer
I would test with real budget devices and network throttling rather than a fast laptop. The priorities become sending less JavaScript, rendering important content on the server, compressing images aggressively, and keeping the initial page under a strict size budget. Caching with a service worker helps repeat visits. Features like large animations and heavy carousels should be reduced or loaded only when the device can handle them.
24

The build works on your machine but fails in CI. How do you troubleshoot?

Save to ▾
Show answer
I would compare environments first: Node version, package manager version, and whether CI uses npm ci with the committed lockfile while I used npm install. Other common causes are case-sensitive file paths on Linux, missing environment variables, and files ignored by Git. Pinning Node with an .nvmrc or engines field and reproducing the CI command locally in a clean clone or container usually reveals the difference.
25

Configure cache headers for hashed assets and HTML in Nginx.

Save to ▾
Show answer
Long cache for fingerprinted files, revalidation for HTML: location ~* \.(js|css|woff2|avif|webp|svg)$ { add_header Cache-Control 'public, max-age=31536000, immutable'; } location / { try_files $uri /index.html; add_header Cache-Control 'no-cache'; } This works only when build tools add content hashes to filenames. Returning users then load assets from cache instantly, while every deploy still reaches them through fresh HTML.
26

Tell me about a frontend architecture decision you led.

Save to ▾
Show answer
Situation: our app's single global store had grown to thousands of lines and slowed every feature. Task: as frontend lead, I had to propose a better structure without stopping delivery. Action: I wrote a short design document comparing options, moved server data to a query cache module by module, and set guidelines for local state. Result: the store shrank by 70 percent and new features took noticeably less time.
27

Marketing has added many third-party scripts and the site has become slow. What do you do?

Save to ▾
Show answer
I would measure each script's cost using the Performance panel and request blocking in DevTools. Then I would remove unused tags, load the rest with async or defer, delay non-essential ones like chat widgets until user interaction or idle time, and use facades, such as a static image for embedded videos. Moving tag management to a server-side setup and agreeing on a script budget with marketing prevents repeat problems.
28

What are CSS cascade layers and what problem do they solve?

Save to ▾
Show answer
Cascade layers, declared with @layer reset, base, components, utilities, let you control the order of priority between groups of styles regardless of selector specificity. A simple selector in a later layer beats a highly specific selector in an earlier layer. This solves specificity wars between resets, third-party libraries and your components, without resorting to !important. Unlayered styles win over all layered ones.
29

What are Proxy and Reflect used for?

Save to ▾
Show answer
A Proxy wraps an object and intercepts operations like get, set, has and deleteProperty through handler traps. Reflect provides matching methods that perform the default behaviour, so traps can add logic and then call Reflect.set. Reactive frameworks such as Vue 3 use Proxies to track which properties a component reads and re-render when they change. Proxies add overhead, so they suit framework internals more than hot loops.
30

Ten teams work on one large frontend and releases keep blocking each other. What would you propose?

Save to ▾
Show answer
I would first try a modular monorepo with clear package boundaries, code owners, affected-only CI with Nx or Turborepo, and trunk-based development with feature flags, which removes most blocking at low cost. If teams truly need independent deployments, I would introduce micro-frontends along business domains, such as search, product and checkout, with a shared design system and strict performance budgets to control duplication.
31

How do you secure a modern frontend application beyond what the framework provides?

Save to ▾
Show answer
Frameworks escape output by default, but risks remain: dangerouslySetInnerHTML or v-html with unsanitised data, javascript: URLs in links, and vulnerable npm packages. I would sanitise any HTML with DOMPurify, enforce a strict Content Security Policy with nonces, use Subresource Integrity for CDN scripts, keep tokens in HttpOnly cookies, run dependency audits in CI and never place secrets in frontend environment variables.
32

Split vendor libraries into separate chunks and visualise the bundle.

Save to ▾
Show answer
Use manualChunks and a visualiser plugin: import { defineConfig } from 'vite'; import { visualizer } from 'rollup-plugin-visualizer'; export default defineConfig({ plugins: [visualizer({ filename: 'stats.html', gzipSize: true })], build: { rollupOptions: { output: { manualChunks: { charts: ['chart.js'], editor: ['@tiptap/core'] } } } } }); After building, open stats.html to see which modules take the most space and decide what to lazy load or replace.
33

Write a polyfill for Promise.all.

Save to ▾
Show answer
Resolve when all succeed, keep result order, reject on first failure: function promiseAll(items) { return new Promise((resolve, reject) => { const results = []; let done = 0; if (items.length === 0) return resolve(results); items.forEach((item, i) => { Promise.resolve(item).then(value => { results[i] = value; if (++done === items.length) resolve(results); }, reject); }); }); } Promise.resolve handles plain values mixed with promises.
34

How did you convince stakeholders to prioritise performance work over new features?

Save to ▾
Show answer
Situation: our product team kept postponing performance fixes for new features. Task: I needed to show the business value. Action: I correlated our real user data with conversion and found that sessions with LCP above 4 seconds converted at about half the rate. I proposed a two-sprint plan with clear targets. Result: leadership approved it, LCP improved by 40 percent and checkout conversion rose measurably.
35

The frontend test suite takes 20 minutes in CI. How do you make it faster?

Save to ▾
Show answer
I would measure which tests are slowest. Options include running tests in parallel and sharding across CI machines, moving logic checks from end-to-end tests into faster integration tests, reusing logged-in state instead of logging in every time, and running only tests affected by changed files on pull requests with the full suite nightly. Replacing real network calls with MSW and caching dependencies also helps.
36

How have you built a testing culture in a frontend team?

Save to ▾
Show answer
Situation: my team had almost no automated tests and frequent regressions. Task: as tech lead, I wanted testing to become a habit, not a mandate. Action: I set up Vitest and Playwright with examples, ran two short workshops, required tests only for bug fixes at first, and celebrated bugs caught in CI. Result: within six months, most pull requests included tests and production regressions dropped significantly.
37

What is hydration and why can it hurt performance?

Save to ▾
Show answer
With server-side rendering, the server sends ready HTML so content appears quickly, but the page is not interactive until the framework downloads JavaScript and hydrates, attaching event listeners and rebuilding state. On slow phones, this causes a gap where buttons look ready but do nothing, hurting INP. Techniques like streaming, partial or progressive hydration, islands architecture and server components reduce how much JavaScript must hydrate.
38

Your app needs to support Hindi and English. How do you design internationalisation?

Save to ▾
Show answer
I would move all UI text into translation files keyed by message ids, use an i18n library that supports plurals and interpolation, and format numbers, dates and currency with Intl APIs for each locale, like en-IN and hi-IN. Layouts must handle longer text and Devanagari fonts with proper line height. The locale goes in the URL, such as /hi/, with hreflang tags for SEO and lang on html.
39

What are declaration files (.d.ts) and when do you write them?

Save to ▾
Show answer
Declaration files describe the types of JavaScript code without containing implementation. Libraries ship them so TypeScript users get type checking, and many come from DefinitelyTyped as @types packages. You write your own when using an untyped library, declaring global variables injected by scripts, or typing non-code imports like declare module '*.svg'. Generating them with declaration: true is standard when publishing a TypeScript library.
40

Management requires 100 percent code coverage, but bugs still appear. How do you respond?

Save to ▾
Show answer
Coverage shows which lines ran, not whether the behaviour was verified, so tests can execute code without meaningful assertions. I would explain this with an example and propose a balanced target, perhaps 80 percent on business logic, combined with quality measures like mutation testing, critical user flows covered by end-to-end tests and tracking escaped defects. Effort is better spent on risky areas than on trivial getters.

Frequently asked questions

What is asked in Frontend Development interviews for 7 years of experience?

Seven-year candidates are evaluated as staff or lead engineers. Expect discussions on multi-team frontend platforms, micro-frontends versus monorepos, long-term technology strategy, engineering standards, and measuring impact through metrics. You should show examples of driving cross-team initiatives such as performance programmes or TypeScript migrations.

How many questions should I practise before a Frontend Development interview?

Work through all 40 questions here, then the company-wise sets for the employers you are targeting. Quality matters more than count: be able to explain why each answer is right.

Which topics matter most for 7 years of experience?

Focus first on Platform strategy, Cross-team initiatives, Engineering standards, Impact measurement.