Google Frontend Interview Questions
Algorithms plus framework-free web fundamentals.
Google hires frontend engineers through broadly the same process as other software engineers, so data structures and algorithms carry a lot of weight. Frontend-focused roles add interviews on JavaScript, the DOM, CSS and web performance.
Interviews are framework-agnostic. You may be asked to build a UI piece or a utility in plain JavaScript, in a shared document without autocomplete, and to explain complexity and trade-offs as you go. React knowledge helps you reason, but it is rarely what is being tested.
- Questions
- 15, 5 with free answers
- Interview rounds
- 5
- Last reviewed
- October 2026
Google frontend interview process
The usual shape of the loop. A guide to what to prepare, not a promise of what you will get.
- 1
Recruiter call
Background, level and which role family fits.
- 2
Technical phone screens
One or two rounds of coding in a shared editor. Usually algorithms, sometimes a frontend problem.
- 3
Interview loop
Typically four or five interviews: algorithm rounds, a frontend or UI coding round, and a system design round for experienced levels.
- 4
Googleyness and leadership
A behavioural interview on collaboration, ambiguity and handling disagreement.
- 5
Hiring committee and team match
Interview feedback is reviewed by a committee, and team matching follows.
What interviewers tend to look for
- Plain JavaScript and DOM APIs, with no framework to lean on.
- Time and space complexity for everything you write.
- Web performance and accessibility, where Google publishes much of the guidance.
- Thinking aloud and testing your own code before the interviewer does.
Your Google mock interview
15 questions. Type an answer under each one and an AI reviewer scores it and tells you what you missed. Stuck on one? Ask for a hint. A free account gets 3 AI replies a day.
Your mock interview
0 of 15 answered
Answer a question and your score shows up here.
JavaScript
7 questions- Question 1 of 15JavaScript
Google interviewer
What is a closure? Give a practical use for one.
Model answer
A closure is a function together with the scope it was created in. The function keeps access to the variables of that scope even after the outer function has returned.
function createCounter() { let count = 0; // private: nothing outside can touch it return { increment: () => ++count, value: () => count, }; } const counter = createCounter(); counter.increment(); counter.value(); // 1Practical uses: private state as above, function factories, and utilities such as
debounceandmemoize, which keep a timer or a cache between calls.The cost to mention: a closure keeps its captured variables alive for as long as the function is reachable, so a long-lived callback holding a large object is a memory leak.
- Question 2 of 15JavaScript
Google interviewer
Explain the event loop. In what order do a setTimeout, a promise callback and synchronous logs run?
Model answer
JavaScript runs on one call stack. When the stack is empty, the event loop first runs every queued microtask (promise callbacks,
queueMicrotask,MutationObserver), then takes one macrotask (a timer, an I/O callback, a UI event), and the browser may render in between.console.log('A'); setTimeout(() => console.log('B'), 0); Promise.resolve().then(() => console.log('C')); console.log('D'); // A, D, C, BSynchronous code finishes first (A, D). The promise callback is a microtask, so it runs before the timer, which is a macrotask, even with a 0 ms delay.
With
asyncfunctions, everything after anawaitis scheduled as a microtask. A common follow-up is a longer snippet mixing both; work through it queue by queue instead of guessing. - Question 3 of 15JavaScript
Google interviewer
How does prototypal inheritance work, and what does the
classsyntax add?Model answer
Every object has a hidden link to another object, its prototype. When you read a property that the object does not have, the engine looks on the prototype, then on that object's prototype, and so on until it finds the property or reaches
null.A function's
prototypeproperty becomes the prototype of the objects it creates withnew. That is how all arrays share one copy ofmap.classis mostly syntax over the same mechanism: methods go on the prototype,extendslinks the chain andsupercalls the parent. It does add a few real things:#privatefields, static blocks, and the rule that a class cannot be called withoutnew.Object.create(proto)creates an object with a chosen prototype directly, andObject.getPrototypeOf(obj)reads it. - Question 4 of 15JavaScript
Google interviewer
What is event delegation? Explain bubbling and capturing.
Model answer
A DOM event travels in three phases: down from
windowto the target (capturing), at the target, then back up towindow(bubbling). Listeners run in the bubbling phase unless you pass{ capture: true }.Delegation uses bubbling: you put one listener on a common ancestor and work out which child was clicked.
list.addEventListener('click', (event) => { const item = event.target.closest('li[data-id]'); if (!item || !list.contains(item)) return; select(item.dataset.id); });Benefits: one listener instead of hundreds, and it keeps working for items added later.
Details that come up:
stopPropagationstops the event travelling,preventDefaultcancels the browser's default action, and a few events such asfocusandblurdo not bubble (usefocusinandfocusout). - Question 5 of 15JavaScript
Google interviewer
Implement an LRU cache with O(1) get and put.
Model answer
A JavaScript
Mapremembers insertion order, so the first key is always the oldest. Deleting and re-inserting a key on every read keeps the least recently used entry at the front.class LRUCache { constructor(capacity) { this.capacity = capacity; this.map = new Map(); } get(key) { if (!this.map.has(key)) return undefined; const value = this.map.get(key); this.map.delete(key); this.map.set(key, value); // now the most recent return value; } put(key, value) { this.map.delete(key); this.map.set(key, value); if (this.map.size > this.capacity) { const oldest = this.map.keys().next().value; this.map.delete(oldest); } } }Many interviewers then ask for the language-independent version: a hash map for lookup plus a doubly linked list for order, with the map pointing at list nodes. Be ready to write that too.
- Question 6 of 15JavaScript
Google interviewer
Run a list of async tasks with at most K running at the same time.
Model answer
async function runWithLimit(tasks, limit) { const results = new Array(tasks.length); let next = 0; async function worker() { while (next < tasks.length) { const index = next++; results[index] = await tasks[index](); } } const workers = Array.from( { length: Math.min(limit, tasks.length) }, worker ); await Promise.all(workers); return results; }tasksmust be functions that return promises. A promise has already started by the time you hold it, so an array of promises cannot be limited.Each worker pulls the next index until none are left.
next++is safe because JavaScript is single-threaded: nothing else runs between reading and incrementing.Follow-ups: keep going when one task fails (catch inside the worker and store the error), add a per-task timeout, and support adding tasks while it runs.
- Question 7 of 15JavaScript
Google interviewer
What causes memory leaks in a frontend app, and how do you find one?
Model answer
A leak is memory that is no longer needed but is still reachable, so the garbage collector cannot free it. Usual causes:
- Event listeners, timers and subscriptions that are never removed.
- DOM nodes removed from the page but still referenced from JavaScript.
- Caches, arrays and maps that only ever grow.
- Closures that keep a large object alive.
- In React, an effect with no cleanup function.
To find one, open the Memory panel in Chrome DevTools. Take a heap snapshot, repeat the suspect action several times (open and close a modal, change route and come back), take another, and compare. Objects whose count keeps growing are the leak; the retainers view shows what holds them.
Fixes: always return a cleanup from effects, cancel requests with
AbortController, and useWeakMaporWeakReffor caches keyed by objects.
TypeScript
1 question- Question 8 of 15TypeScript
Google interviewer
What are generics, and how do you constrain one?
Model answer
A generic is a type parameter. It lets a function or type work with many types while keeping the link between its inputs and its output, which
anythrows away.function first<T>(items: T[]): T | undefined { return items[0]; } first([1, 2, 3]); // number | undefined first(['a', 'b']); // string | undefinedA constraint with
extendslimits what the parameter can be, and lets you use the properties that the constraint guarantees:function pluck<T, K extends keyof T>(items: T[], key: K): T[K][] { return items.map((item) => item[key]); } pluck([{ id: 1, name: 'Asha' }], 'name'); // string[] pluck([{ id: 1, name: 'Asha' }], 'age'); // compile errorGood to mention: type arguments are usually inferred, generics can have defaults (
<T = string>), and one that is used only once in a signature is usually not needed.
React
1 question- Question 9 of 15React
Google interviewer
How does React decide what to update in the DOM? Why do list items need keys?
Model answer
Rendering calls your components and produces a tree of elements. React compares that tree with the previous one (reconciliation) and then applies only the differences to the DOM, in a separate commit step.
Two rules keep the comparison fast:
- A different element type at the same position (a
divbecoming asection, orLoginbecomingDashboard) means React throws that subtree away and builds a new one. Its state is lost. - The same type at the same position means React keeps the instance and its state and updates the props.
In a list, position is not enough, because items move. A
keytells React which item is which between renders. With the array index as the key, inserting at the top makes every item look changed, and state such as a typed input value ends up attached to the wrong row. Use a stable id from the data.A useful trick follows from the same rule: changing a component's
keyon purpose resets its state. - A different element type at the same position (a
CSS
2 questions- Question 10 of 15CSS
Google interviewer
Explain the position values. Why does z-index sometimes not work?
Model answer
static: the default. Offsets andz-indexhave no effect.relative: stays in the flow and can be nudged. It also becomes the reference for absolutely positioned children.absolute: removed from the flow and placed relative to the nearest positioned ancestor.fixed: placed relative to the viewport, unless an ancestor has atransformorfilter, which captures it.sticky: behaves as relative until it reaches the offset you give it (top: 0), then sticks inside its scrolling ancestor. It fails without an offset, or when an ancestor hasoverflow: hidden.
z-indexonly orders elements inside the same stacking context. A new context is created by a positioned element with az-index, byopacitybelow 1, and bytransform,filterandisolation: isolate, among others.So a modal with
z-index: 9999can still sit under a header withz-index: 2, if the modal is inside a parent that forms its own context and that parent is below the header. The fix is to move the element out, usually with a portal, or to change the parent's stacking order. - Question 11 of 15CSS
Google interviewer
What is the difference between reflow and repaint? How do you keep animations smooth?
Model answer
The browser renders in steps: style, layout, paint, composite.
- Changing geometry (
width,top,margin, font size, adding nodes) forces layout, also called reflow, for the affected part of the tree, and then a repaint. - Changing appearance only (
color,background,box-shadow) skips layout but still repaints. - Changing
transformoropacitycan be done by the compositor alone, without layout or paint. These are the properties to animate.
/* Janky: recalculates layout every frame */ .panel { transition: left 200ms; } /* Smooth: handled by the compositor */ .panel { transition: transform 200ms; } .panel.open { transform: translateX(240px); }Layout thrashing is the other common cause of jank. Reading a layout value such as
offsetHeightorgetBoundingClientRect()straight after writing a style forces the browser to run layout immediately. In a loop that is one forced layout per iteration. Do all the reads first, then all the writes, or schedule writes inrequestAnimationFrame.will-changehints that an element will animate. Use it on a few elements, since each one takes memory. - Changing geometry (
Browser, performance and system design
4 questions- Question 12 of 15Browser, performance and system design
Google interviewer
What happens between typing a URL and seeing the page?
Model answer
- DNS turns the domain into an IP address.
- The browser opens a connection: a TCP and TLS handshake, or QUIC for HTTP/3.
- It sends the request and the server starts streaming HTML back.
- The parser builds the DOM as HTML arrives. CSS is downloaded and parsed into the CSSOM. CSS blocks rendering, and a plain
scripttag blocks the parser until it has downloaded and run. - DOM and CSSOM are combined into the render tree, which holds only what is visible.
- Layout works out the size and position of every box, paint fills in the pixels, and compositing puts the layers on screen.
- JavaScript then runs, and in a framework app it hydrates the page so that it responds to input.
This sequence is called the critical rendering path. Most performance work is shortening it: fewer and smaller render-blocking files,
deferon scripts, inlining the CSS needed for the first screen, compression, a CDN close to the user, and caching so that repeat visits skip the network.Interviewers often pick one step and go deeper, so know at least one well.
- Question 13 of 15Browser, performance and system design
Google interviewer
What are the Core Web Vitals, and how do you improve each one?
Model answer
- LCP (Largest Contentful Paint): when the largest image or text block in the first screen is drawn. Good is 2.5 seconds or less. Improve it with a faster server response, a correctly sized and prioritised hero image, fewer render-blocking files, and server-rendered content.
- INP (Interaction to Next Paint): how long the page takes to visibly respond to a click, tap or key press. It replaced FID in 2024. Good is 200 ms or less. Improve it by breaking up long tasks, shipping less JavaScript, avoiding large re-renders on input, and moving heavy work off the main thread.
- CLS (Cumulative Layout Shift): how much content moves unexpectedly. Good is 0.1 or less. Improve it by giving images, ads and embeds a reserved size, by not inserting content above what the user is reading, and by loading fonts with matching fallbacks.
Each is judged at the 75th percentile of real visits, not the average.
Know the two kinds of data. Lab data from Lighthouse is one run on one simulated device, useful for debugging. Field data from real users, collected with the
web-vitalslibrary or from the Chrome UX Report, is what counts. INP in particular can only be measured properly in the field. - Question 14 of 15Browser, performance and system design
Google interviewer
How do you make a web page accessible?
Model answer
- Use the right HTML element. A
buttonis focusable, works with Enter and Space and is announced as a button. Adivwith a click handler does none of that. The same goes fornav,main, headings in order, and alabelfor every input. - Keyboard. Everything must be reachable and usable without a mouse, in a sensible order, with a visible focus ring. When a dialog opens, move focus into it, keep it there, and return it to the trigger on close.
- Text alternatives. Images need
alttext, or an emptyaltif they are decorative. Icon-only buttons need an accessible name. - Colour. Body text needs a contrast ratio of at least 4.5 to 1, and colour should never be the only signal.
- ARIA, when HTML is not enough.
aria-expandedon a toggle,aria-livefor updates that appear without a page load, roles for custom widgets. No ARIA is better than wrong ARIA. - Motion and zoom. Respect
prefers-reduced-motion, and make sure the page works at 200% zoom.
For testing: use the page with the keyboard only, run an automated checker such as axe or Lighthouse, and try a screen reader on the main flows. Automated tools catch only part of the problems.
- Use the right HTML element. A
- Question 15 of 15Browser, performance and system design
Google interviewer
Frontend system design: design a search autocomplete.
Model answer
Begin with questions: how many results, what is being searched, mobile or desktop, is offline needed, are results personalised.
- Component API: a controlled input, a
fetchSuggestions(query)function, arenderItemslot, anonSelectcallback and a minimum query length. - Network: debounce input by about 300 ms. Cancel the previous request with
AbortController, or ignore any response that is not for the latest query. Out-of-order responses are the classic bug here. - Cache: keep results per query in memory with a size limit and an expiry, so that deleting a character is instant.
- States: idle, loading, results, no results, error with retry.
- Keyboard and accessibility: Up and Down move the highlight, Enter selects, Escape closes. Use the combobox pattern:
role="combobox",aria-expanded,aria-controlsandaria-activedescendant. - Rendering: highlight the matching part safely, without
innerHTML, and virtualise the list if it can be long. - Server contract: prefix search with a limit, ranked results, short cache headers.
End with what you would measure, such as time to first suggestion and how often a suggestion is picked, and what you left out on purpose.
- Component API: a controlled input, a
Practise for Google
Reading answers is the easy half. These problems run in the browser against real tests.
