Frontend Development Interview Questions for Freshers
40 questions with answers for candidates with Freshers — 23 easy, 17 medium.
What interviewers expect: freshers
Freshers are tested on JavaScript fundamentals such as closures, the event loop, promises and array methods, along with CSS layouts, basic TypeScript and DOM work. Expect a live coding task like debounce or a small UI component, plus questions about your projects. Interviewers look for clear thinking and clean code rather than framework trivia.
This set is weighted towards Modern JavaScript (10), Build Tools and Tooling (7), Frontend Testing (6), TypeScript (6).
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
Why are dvh and svh units better than vh on mobile?
On mobile browsers, 100vh equals the height with the address bar hidden, so a full-screen section gets cut off when the bar is visible. svh is the small viewport height with browser UI shown, lvh the large one, and dvh updates dynamically as the bar appears or hides. Using min-height: 100dvh for hero sections or app shells prevents content hiding behind browser chrome.
Vitest reuses the Vite configuration and transform pipeline, so TypeScript, JSX, ES modules and path aliases work without separate Babel or ts-jest setup. It is fast thanks to on-demand transformation and smart watch mode, and its API is largely compatible with Jest, making migration easy. Jest remains mature and widely used, especially in projects not built with Vite. Both support mocking, snapshots and coverage.
:has() is often called the parent selector because it styles an element based on what it contains or what follows it. For example, .card:has(img) can change padding for cards with images, and form:has(input:invalid) can highlight a form with errors. It removes many cases where JavaScript was used only to toggle classes. It is supported in all modern browsers.
04
How can web fonts slow a page down and how do you optimise them?
Fonts are often discovered late, after CSS is parsed, and text may stay invisible until they load. To optimise, self-host fonts in WOFF2 format, subset them to the characters you need, preload the main weight, and use font-display: swap so fallback text appears immediately. Limiting the number of weights and using variable fonts reduces downloads. Matching fallback metrics with size-adjust prevents layout shift.
05
Model API request state with a discriminated union.
A shared status field lets TypeScript narrow each case:
type ApiState<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; message: string };
function render(state: ApiState<string[]>) {
switch (state.status) {
case 'success': return state.data.join(', ');
case 'error': return 'Error: ' + state.message;
default: return 'Loading...';
}
}
Impossible states, like having both data and an error, cannot be represented.
A Progressive Web App is a website that behaves like an installable app. It needs HTTPS, a web app manifest with name, icons and theme colour, and usually a service worker for offline support and caching. Users can add it to their home screen and it opens in a standalone window. PWAs are popular in India for lightweight apps that work on low-end phones and patchy mobile networks.
07
QA reports a bug that happens only in Safari on iPhone. How do you debug it?
I would reproduce it on a real iPhone or simulator and connect Safari Web Inspector from a Mac to see console errors and network requests. Common causes are unsupported APIs, date parsing differences, 100vh and viewport issues, and input zoom on small fonts. Cloud device platforms help if no device is available. After fixing it, I would add WebKit to the Playwright browser matrix to catch similar issues.
08
Compare Promise.all, Promise.allSettled, Promise.race and Promise.any.
Promise.all resolves with all results when every promise succeeds, but rejects immediately if any fails. Promise.allSettled always waits for all and returns each outcome with status fulfilled or rejected, useful for dashboards loading independent widgets. Promise.race settles with the first promise to settle, often used for timeouts. Promise.any resolves with the first success and rejects only if all fail, useful for trying multiple mirrors.
09
How does the History API enable client-side routing?
history.pushState(state, '', '/courses/react') changes the URL and adds a history entry without reloading the page, and replaceState updates the current entry. When users press back or forward, the popstate event fires and the app renders the matching view. The server must return the app's HTML for all routes, otherwise refreshing a deep link gives a 404. Routers in SPA frameworks are built on this API.
Snapshot tests save a component's rendered output and fail when it changes, which quickly detects unintended changes with little effort. However, large snapshots are hard to review, so developers often update them blindly, and they break on harmless markup changes. They work best for small, stable outputs like serialised config or error messages. For UI behaviour, explicit assertions on visible text and roles are more meaningful.
11
Implement a copy-to-clipboard button with user feedback.
The async Clipboard API works in secure contexts after a user action:
copyBtn.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(couponCode.textContent);
copyBtn.textContent = 'Copied!';
} catch {
copyBtn.textContent = 'Press Ctrl+C to copy';
}
setTimeout(() => (copyBtn.textContent = 'Copy code'), 2000);
});
An aria-live region can announce 'Copied' to screen reader users, since a changing button label may not always be read out.
12
What do caret and tilde mean in package versions, and why commit the lockfile?
Versions follow semantic versioning: major.minor.patch. ^1.4.2 allows any 1.x.x version at or above 1.4.2, and ~1.4.2 allows only patch updates within 1.4.x. Because ranges can resolve differently over time, the lockfile, such as package-lock.json or pnpm-lock.yaml, records exact installed versions. Committing it and using npm ci in CI ensures every developer and build uses identical dependencies.
13
Write a Vitest unit test for an INR price formatter.
A pure function returns the same output for the same input and has no side effects such as changing external variables. Immutability means creating new objects instead of modifying existing ones, for example using spread syntax to update state. Together they make code predictable and easy to test, and they let frameworks detect changes with a simple reference comparison, which enables efficient re-rendering.
A higher-order function takes a function as an argument or returns one, like map, filter or a custom withLogging(fn) wrapper. Currying transforms a function with many arguments into a chain of single-argument functions, so add(2)(3) returns 5. Currying makes partial application easy, for example creating formatINR = formatCurrency('INR') once and reusing it. Overusing it can reduce readability for teams unfamiliar with functional style.
16
Why do you want to build a career in frontend development?
I like work where users see the result directly. In college I built a timetable app for my class, and watching classmates use it daily taught me how small UI details matter. Frontend combines logic, design and performance, and the ecosystem keeps evolving, which keeps me learning. I want to build fast, accessible interfaces for products used by millions of people across India.
17
How do you handle a situation where a bug you wrote affected users?
Situation: a form validation change I made blocked some users from signing up with valid numbers. Task: I needed to fix it and be transparent. Action: I informed my lead immediately, rolled back the change, found that my regex rejected numbers with a +91 prefix, fixed it, and added tests for different formats. Result: signups recovered within an hour, and I now test with real-world data samples.
18
Flatten a deeply nested array without using Array.prototype.flat.
A recursive reduce handles any depth:
function flatten(arr) {
return arr.reduce((acc, item) =>
Array.isArray(item) ? acc.concat(flatten(item)) : acc.concat(item), []);
}
flatten([1, [2, [3, [4]], 5]]); // [1, 2, 3, 4, 5]
In real code, arr.flat(Infinity) does the same. For extremely deep nesting, an iterative version with a stack avoids call stack overflow.
19
When should you use Map and Set instead of plain objects and arrays?
Map allows keys of any type, keeps insertion order, has a size property and performs well with frequent additions and deletions, so it suits caches and lookups by object. Set stores unique values with fast has() checks, ideal for tracking selected ids. Plain objects are better for fixed-shape records and JSON. Arrays are better when order and index access matter and duplicates are allowed.
Powerful features require user consent, a secure HTTPS context and usually a user gesture. Calling navigator.geolocation.getCurrentPosition or Notification.requestPermission shows a browser prompt; if the user denies it, you cannot ask again easily. navigator.permissions.query lets you check the current state first. Good UX explains why you need the permission before triggering the prompt, for example asking for location only when the user taps 'Find nearest centre'.
22
How would you explain a difficult JavaScript concept to a junior teammate?
Situation: a junior developer kept writing bugs with async code. Task: I wanted them to understand promises rather than copy fixes. Action: I drew the event loop on a whiteboard, wrote three small console examples for them to predict, and then reviewed one of their real pull requests together. Result: within two weeks, their async bugs stopped and they started explaining the concept to the next new joiner.
23
A dashboard must show live order updates. Would you use polling, Server-Sent Events or WebSockets?
Polling is simplest and fine if updates every 30 seconds are acceptable. Server-Sent Events push one-way updates from server to browser over HTTP with automatic reconnection, ideal for live orders, notifications and stock tickers. WebSockets provide full two-way communication, needed for chat or collaborative editing, but require more infrastructure. For a one-way dashboard, I would choose SSE and reconnect gracefully on network changes.
24
Make an embedded video keep a 16:9 ratio at any width.
Generics let you write reusable code that keeps type information, using type parameters like <T>. For example, function first<T>(items: T[]): T | undefined returns a number for a number array and a User for a User array without losing types. Constraints such as <T extends { id: string }> restrict what T can be. Generics power typed API clients, form libraries and reusable UI components.
any turns off type checking completely, so errors slip through silently. unknown also accepts any value, but you must narrow it with typeof, instanceof or a type guard before using it, which makes it the safe choice for API responses and catch errors. never represents values that never occur, such as a function that always throws, or the leftover case in an exhaustive switch over a union.
27
What is the guiding principle of Testing Library and why query by role?
Testing Library encourages testing the way users interact: find elements by what they see and hear, not by implementation details like class names or component internals. getByRole('button', { name: 'Submit' }) is preferred because it also verifies the element is accessible. Tests written this way survive refactors and catch real accessibility problems. Test ids are a last resort when no accessible query works.
28
Write a custom type guard to check if a value is a User.
A function returning value is User narrows the type:
interface User { id: number; email: string; }
function isUser(value: unknown): value is User {
return typeof value === 'object' && value !== null &&
'id' in value && typeof (value as User).id === 'number' &&
'email' in value && typeof (value as User).email === 'string';
}
const data: unknown = JSON.parse(raw);
if (isUser(data)) console.log(data.email);
Inside the if block, data is treated as User.
29
Why do build tools add content hashes to filenames?
A content hash, like main.8c1f2a.js, changes only when the file's contents change. This lets servers cache assets for a year without worrying about stale code, because a new deploy references new filenames from fresh HTML. Unchanged chunks keep their hashes, so users re-download only what changed. Splitting vendor code into its own chunk improves this, since libraries change less often than app code.
30
How does client-side rendering affect SEO and social sharing?
With pure client-side rendering, the initial HTML is mostly empty and content appears after JavaScript runs. Google can render JavaScript, but it happens later and less reliably, while many social media link previewers and some search engines do not run JavaScript at all, so titles and images are missing. Server rendering or prerendering important pages ensures content and meta tags are in the initial HTML.
31
The build works on your machine but fails in CI. How do you troubleshoot?
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.
32
Predict the output order of synchronous code, promises and setTimeout.
Synchronous code runs first, then microtasks, then macrotasks:
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
queueMicrotask(() => console.log('D'));
console.log('E');
// Output: A, E, C, D, B
A and E are synchronous. C and D are microtasks queued in order. B is a macrotask and waits until the microtask queue is empty, even with a 0 ms delay.
33
Tell me about a time you convinced your team to adopt a new tool like TypeScript.
Situation: our JavaScript app kept breaking after API changes. Task: I believed TypeScript would help but the team worried about slowing down. Action: I converted one small module as a pilot, showed three bugs it caught, and proposed gradual adoption with no deadline pressure. Result: the team agreed, we migrated over two quarters, and production errors related to wrong data shapes dropped significantly.
34
Create a new Vite project with TypeScript and run it.
Use the official scaffolding tool:
npm create vite@latest my-app -- --template vanilla-ts
cd my-app
npm install
npm run dev # starts the dev server with HMR
npm run build # type-checks and builds to dist/
npm run preview # serves the production build locally
Templates also exist for react-ts, vue-ts and svelte-ts. The dist folder contains static files ready for any web server or CDN.
35
What are source maps and should they be deployed to production?
Source maps link minified production code back to the original source files and line numbers, so DevTools and error trackers show readable stack traces. They are generated by the bundler as .map files. Many teams upload them privately to monitoring tools like Sentry and do not serve them publicly, which keeps original source code less exposed while still allowing debugging of production errors.
Destructuring pulls values out of arrays or objects into variables. Defaults apply only when the value is undefined, not when it is null. For example, const { name, city = 'Delhi' } = user sets city to Delhi if the property is missing. Function parameters can be destructured too, like function render({ title, size = 'md' } = {}), which avoids errors when no argument is passed and documents expected options clearly.
npm comes with Node and is the default. pnpm stores each package version once in a global content-addressable store and links it into projects, saving disk space and installing faster, and its strict node_modules layout prevents using undeclared dependencies. Yarn offers workspaces and Plug'n'Play mode. All three support workspaces for monorepos. pnpm has become very popular for large projects because of speed and strictness.
38
Explain optional chaining and the nullish coalescing operator.
Optional chaining ?. stops evaluation and returns undefined if the value before it is null or undefined, so user?.address?.pincode never throws. Nullish coalescing ?? returns the right side only when the left is null or undefined, unlike || which also replaces 0, false and empty strings. For example, const qty = input ?? 1 keeps a valid 0, while input || 1 would wrongly change 0 into 1.
39
Product images on a listing page load slowly. What quick fixes would you apply?
I would convert images to WebP or AVIF, resize them to the actual thumbnail size instead of loading full product photos, and serve them through srcset. Images below the fold get loading='lazy', while the first few visible ones load eagerly. Adding width and height prevents layout shift, and serving images from a CDN with long cache headers makes repeat visits much faster.
Let callers specify the expected response type:
async function getJson<T>(url: string): Promise<T> {
const res = await fetch(url);
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
return res.json() as Promise<T>;
}
interface Course { id: number; title: string; }
const courses = await getJson<Course[]>('/api/courses');
courses[0].title.toUpperCase();
The cast trusts the server, so for untrusted data validate with a schema library like Zod before returning.
Frequently asked questions
What is asked in Frontend Development interviews for Freshers?
Freshers are tested on JavaScript fundamentals such as closures, the event loop, promises and array methods, along with CSS layouts, basic TypeScript and DOM work. Expect a live coding task like debounce or a small UI component, plus questions about your projects. Interviewers look for clear thinking and clean code rather than framework trivia.
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 Freshers?
Focus first on JavaScript fundamentals, CSS layouts, Basic TypeScript, Project walkthroughs.