
These are the frontend interview questions I’d study if I had a loop next month: 300+ of them, covering everything a frontend round can throw at you, from HTML semantics to frontend system design. Every question has a direct answer, many have code, and most link to a FrontendLead problem or deep dive so you can practice instead of just reading.
Frontend interviews are broader than most software interviews. In one loop you can get a CSS layout question, a “what happens when you type a URL” question, a React component to build in 45 minutes, and a system design round. This list follows that shape. If you want to go deeper on one area, the JavaScript interview questions and React interview questions guides each have 300+ more. For official references while you study, use MDN Web Docs.
What to Expect
- 12 sections in the order most interviews go: HTML, CSS, layout, JavaScript, the browser, frameworks, performance, accessibility, security, testing, UI coding, and senior questions.
- Direct answers first, then the detail that separates a pass from a strong pass: code, trade-offs, and what the interviewer is checking.
- Frontend coding interview questions for UI components (autocomplete, modal, tabs, data table) with the key ideas and links to build them in the browser.
- Senior frontend interview questions on system design, architecture, and behavioral rounds.
Short on time? How to Use This List at the end has a study order by level.
Jump to a section
- HTML Interview Questions: Semantics and Forms (Q1-30)
- CSS Interview Questions: Cascade, Box Model, and Positioning (Q31-65)
- Layout: Flexbox, Grid, and Responsive Design (Q66-95)
- JavaScript Essentials for Frontend Interviews (Q96-125)
- How Browsers Work: Rendering, Networking, and Storage (Q126-160)
- Frameworks: React, Vue, and Angular Concepts (Q161-185)
- Web Performance and Core Web Vitals (Q186-210)
- Accessibility Interview Questions (Q211-230)
- Frontend Security: XSS, CSRF, CSP, and CORS (Q231-245)
- Testing, Tooling, and Git (Q246-260)
- Frontend Coding Interview Questions: UI Components (Q261-285)
- Senior Frontend Interview Questions: System Design and Behavioral (Q286-305)
HTML Interview Questions: Semantics and Forms

Find in-depth explanations and practice here: HTML interview questions in the handbook ->
HTML questions look easy, which is why candidates lose points on them. Interviewers check whether you pick the right element for the job, because the right element gives you accessibility, SEO, and keyboard support for free.
1. What does <!DOCTYPE html> do?
It tells the browser to render the page in standards mode. Without it, browsers fall back to quirks mode, which emulates old browser bugs (for example, a different box model for some elements), so layouts break in surprising ways. It isn’t an HTML tag; it’s an instruction to the parser.
2. What is semantic HTML, and why does it matter?
Semantic HTML uses elements that describe what content is (<nav>, <article>, <button>) rather than how it looks (<div> with a class). It matters for three reasons: screen readers announce roles and let users jump between landmarks, search engines understand the page structure, and native elements come with built-in behavior like keyboard focus.
Deep dive: Semantic markup
3. What are landmark elements?
<header>, <nav>, <main>, <aside>, <footer>, plus <section> and <form> when they have an accessible name. Screen reader users can list landmarks and jump straight to the main content. Use one <main> per page.
4. What is the difference between <section>, <article>, and <div>?
| Element | Use it for |
|---|---|
<article> |
Self-contained content that makes sense on its own: a blog post, a comment, a product card |
<section> |
A thematic group of content with its own heading |
<div> |
A generic wrapper with no meaning, for styling or layout only |
5. What is the difference between block and inline elements?
Block elements (div, p, h1) start on a new line and take the full available width; width and height apply. Inline elements (span, a, strong) flow within text and only take the space their content needs; width, height, and vertical margins don’t apply. inline-block flows inline but accepts width and height.
Deep dive: Block vs inline elements
6. What is the difference between an attribute and a property?
Attributes are written in the HTML and are always strings. Properties live on the DOM object and can be any type. They’re linked but not identical: input.getAttribute("value") returns the initial value from the HTML, while input.value returns what the user has typed.
Deep dive: Attributes vs properties
7. What are data-* attributes for?
Custom data attributes store extra information on an element without abusing class or id. Read them in JavaScript through element.dataset (data-user-id becomes dataset.userId) and target them in CSS with attribute selectors. Don’t store sensitive data in them; they’re visible in the page source.
8. What is the difference between script, script async, and script defer?
| Attribute | Download | Runs | Order |
|---|---|---|---|
| none | Blocks parsing | Immediately | In order |
async |
In parallel | As soon as it downloads, pausing parsing | Not guaranteed |
defer |
In parallel | After parsing, before DOMContentLoaded |
In order |
Use defer for app code that needs the DOM, and async for independent scripts like analytics. Module scripts (type="module") are deferred by default.
9. Why put CSS in the head and scripts at the end of the body (or deferred)?
CSS in the head lets the browser build the CSSOM early and avoids a flash of unstyled content. A plain script blocks HTML parsing while it downloads and runs, so placing it at the end, or using defer, lets the page render first.
10. What are the important tags in the document head?
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Page title shown in tabs and search results</title>
<meta name="description" content="Search result snippet" />
<link rel="canonical" href="https://example.com/page" />
<meta property="og:image" content="https://example.com/share.png" />
The viewport tag is the one candidates forget: without it, mobile browsers render the page at desktop width and zoom out.
11. What do preload, prefetch, and preconnect do?
preconnect opens the connection (DNS, TCP, TLS) to an origin you’ll need soon. preload fetches a resource the current page needs early, such as the hero image or a font. prefetch fetches, at low priority, a resource the next page will probably need. Overusing preload competes with critical resources and makes things slower.
12. How do you make images responsive in HTML?
Use srcset and sizes so the browser picks the right resolution, and <picture> when you need different crops or formats. Always set width and height to reserve space and avoid layout shift.
<img src="hero-800.jpg"
srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1600.jpg 1600w"
sizes="(max-width: 600px) 100vw, 50vw"
width="800" height="450" alt="Team planning a sprint at a whiteboard" />
Deep dive: Image optimization strategies
13. What makes good alt text?
Describe what the image communicates in context, not what it is (“Chart: sales doubled in Q3”, not “chart.png”). Decorative images get an empty alt="" so screen readers skip them. Leaving alt off entirely makes screen readers read the filename.
14. What does loading="lazy" do?
It defers loading images and iframes until they’re near the viewport, saving bandwidth on long pages. Don’t lazy-load the main above-the-fold image: it delays Largest Contentful Paint. For that image, use fetchpriority="high" instead.
15. What is the difference between <button> and a clickable <div>?
A button is focusable, activates with Enter and Space, has the button role for screen readers, and can submit forms. A div has none of that; you’d need tabindex, a role, and key handlers to rebuild it, and it’s still easy to get wrong. Use buttons for actions and links (<a href>) for navigation.
16. What is the default type of a button inside a form?
submit. A button inside a form submits it unless you set type="button". This causes the classic “the page reloads when I click Cancel” bug.
17. How do you associate a label with an input?
<label for="email">Email</label>
<input id="email" name="email" type="email" autocomplete="email" required />
<!-- or wrap it -->
<label><input type="checkbox" name="terms" /> I accept the terms</label>
Labels give the input an accessible name and make the label text clickable, which matters for small checkboxes. A placeholder is not a label: it disappears when the user types.
18. What built-in form validation does HTML provide?
Attributes like required, type="email", min/max, minlength, and pattern. The browser blocks submission and shows messages, and CSS can style :invalid and :user-invalid states. In JavaScript, input.setCustomValidity() and form.reportValidity() give you control. Always validate on the server too: client-side validation is for user experience, not security.
Practice: Signup Form
19. Why use specific input types like email, tel, and number?
They show the right keyboard on mobile, enable built-in validation, and help autofill. Be careful with type="number" for things like credit cards or ZIP codes: they aren’t quantities, and the browser may strip leading zeros. Use inputmode="numeric" with a text input instead.
20. What does the autocomplete attribute do?
It tells the browser what kind of data a field holds (email, new-password, one-time-code, street-address) so it can autofill correctly. Good autocomplete values make checkout and signup much faster, and password managers rely on them.
21. What is the difference between GET and POST form submissions?
GET puts form data in the URL query string; use it for searches and filters that should be bookmarkable. POST sends data in the request body; use it for anything that changes data on the server. GET requests can be cached and appear in history and server logs, so never use GET for passwords.
Deep dive: HTTP GET vs POST
22. What are <fieldset> and <legend> for?
They group related controls, such as a set of radio buttons, and give the group a name. Screen readers announce the legend when focus enters the group, so “Shipping speed: Express” makes sense. <fieldset disabled> also disables every control inside it.
23. What are <dialog> and <details>?
<dialog> is a native modal: showModal() traps focus, closes on Escape, adds a backdrop, and makes the rest of the page inert. <details> with <summary> is a native disclosure widget (expand and collapse) that works without JavaScript. Knowing these shows you don’t reach for a library by default.
24. What is the difference between <strong> and <b>, and <em> and <i>?
<strong> means importance and <em> means stress emphasis; both carry meaning. <b> and <i> are stylistic offsets without extra importance, such as a keyword or a term in another language. Visually they often look the same.
25. How should you structure headings?
One <h1> describing the page, then <h2> to <h6> in order without skipping levels for styling. Screen reader users navigate by headings, and search engines use them to understand structure. Choose the level by hierarchy, then style it with CSS.
Practice: Heading Outline Tree
26. What is the difference between <iframe> and <embed>, and what are iframe risks?
An iframe embeds a full separate document, such as a video player or a payment form. The risks are clickjacking (your page framed by an attacker) and untrusted embedded content. Use the sandbox attribute to restrict what embedded content can do, and send X-Frame-Options or CSP frame-ancestors headers to control who can frame your pages.
27. What are Web Components?
A set of browser standards for reusable custom elements: Custom Elements (customElements.define), Shadow DOM (encapsulated markup and styles), and <template>/<slot>. They work in any framework or none, which makes them a good fit for design systems shared across teams.
class HelloBadge extends HTMLElement {
connectedCallback() {
const root = this.attachShadow({ mode: "open" });
root.innerHTML = `<style>span { color: teal; }</style><span>Hello, ${this.getAttribute("name")}</span>`;
}
}
customElements.define("hello-badge", HelloBadge);
// <hello-badge name="Ada"></hello-badge>
28. What is the Shadow DOM?
A hidden DOM tree attached to an element. Styles inside it don’t leak out, and page styles don’t leak in (except inherited properties like color and CSS custom properties). That’s how native elements like <video> have internal controls you can’t accidentally restyle.
29. What HTML matters for SEO?
A unique <title> and meta description, one clear <h1>, logical headings, descriptive link text (not “click here”), alt text, a canonical URL, real <a href> links that crawlers can follow, and structured data (JSON-LD) for rich results. Content that only appears after client-side JavaScript runs may be indexed late, which is one reason for server rendering.
30. What is progressive enhancement in HTML terms?
Build the core experience with HTML that works on its own (a real form with an action, real links), then add CSS and JavaScript on top. If the script fails to load, the user can still complete the task.
Deep dive: Progressive enhancement vs graceful degradation
CSS Interview Questions: Cascade, Box Model, and Positioning

Find in-depth explanations and practice here: CSS interview questions in the handbook ->
CSS questions separate people who write CSS from people who understand it. Expect “why doesn’t this work” questions: why z-index is ignored, why margins collapse, why a style doesn’t apply.
31. What is the CSS box model?
Every element is a box made of content, padding, border, and margin, from the inside out. By default (box-sizing: content-box), width sets only the content width, so padding and border are added on top. With box-sizing: border-box, width includes padding and border, which is why most resets apply it to everything.
*, *::before, *::after { box-sizing: border-box; }
.card { width: 300px; padding: 20px; border: 2px solid; } /* still 300px wide */
32. How does the cascade decide which rule wins?
In order: origin and importance (user-agent, user, author styles, with !important reversing the order), then cascade layers (@layer), then specificity, then source order (later wins). Inline styles beat selectors unless the selector rule uses !important.
33. How is specificity calculated?
As three numbers compared left to right: IDs, then classes/attributes/pseudo-classes, then elements/pseudo-elements. #nav .item a is (1, 1, 1) and beats .nav .item a at (0, 2, 1). The universal selector and combinators add nothing. :where() contributes zero specificity, while :is() and :not() take the specificity of their most specific argument.
| Selector | Specificity |
|---|---|
p |
0, 0, 1 |
.btn:hover |
0, 2, 0 |
#header .logo img |
1, 1, 1 |
:where(#header) a |
0, 0, 1 |
34. Why is !important discouraged?
It breaks the normal cascade, and the only way to override it is another !important with equal or higher specificity, which escalates into an unmaintainable mess. Legitimate uses: utility classes that must always apply, and overriding third-party styles you can’t change. Cascade layers are usually the cleaner fix.
35. What are cascade layers (@layer)?
Layers let you order groups of styles explicitly, so a later layer wins regardless of specificity in earlier layers. That solves the “my reset is too specific” and “third-party CSS beats mine” problems without specificity wars.
@layer reset, vendor, components, utilities;
@layer components { #app .button { color: navy; } }
@layer utilities { .text-red { color: red; } } /* wins: later layer */
36. Which properties inherit?
Mostly text-related ones: color, font-*, line-height, text-align, visibility, cursor, and custom properties. Box properties like margin, padding, border, and background don’t. You can force it with inherit, and reset with initial, unset, or revert.
37. What is margin collapsing?
Vertical margins between adjacent block elements combine into one margin equal to the larger value, instead of adding up. It also happens between a parent and its first or last child when nothing (padding, border, or a new formatting context) separates them. It doesn’t happen in flex or grid containers, or with horizontal margins.
38. What is a block formatting context (BFC)?
An isolated layout region where floats are contained and margins don’t collapse through the boundary. display: flow-root creates one with no side effects; overflow: hidden, flex and grid items, and absolutely positioned elements also create one. It’s the modern fix for parents that collapse around floated children.
Deep dive: Block formatting context
39. What are the values of position?
| Value | Positioned relative to | In normal flow? |
|---|---|---|
static |
Not positioned (default) | Yes |
relative |
Its own normal position | Yes, space is kept |
absolute |
Nearest positioned ancestor | No |
fixed |
The viewport (or a transformed ancestor) | No |
sticky |
Acts relative until a scroll threshold, then sticks within its container | Yes |
40. Why isn’t my position: sticky element sticking?
Usual causes: no top (or other inset) value, an ancestor with overflow: hidden or auto that becomes the scroll container, or a parent that’s only as tall as the sticky element so there’s no room to stick.
41. Why doesn’t z-index work?
Two common reasons. It only applies to positioned elements and flex or grid items. And it only competes within the same stacking context: a child with z-index: 9999 can’t escape a parent whose stacking context sits below a sibling. New stacking contexts come from position plus z-index, opacity below 1, transform, filter, isolation: isolate, and will-change.
42. What is a stacking context?
A group of elements that are layered together as one unit. Inside it, children are ordered by z-index, but the whole group sits at its parent’s layer. Think of folders: you can reorder pages inside a folder, but a page can’t move above a folder that’s on top of its own.
43. How do you center an element horizontally and vertically?
/* Flexbox */
.parent { display: flex; justify-content: center; align-items: center; }
/* Grid: shortest version */
.parent { display: grid; place-items: center; }
/* Absolute positioning, unknown size */
.child { position: absolute; inset: 0; margin: auto; width: fit-content; height: fit-content; }
For a single line of inline text, text-align: center handles horizontal centering. Interviewers like hearing more than one approach and when each fits.
44. What is the difference between display: none, visibility: hidden, and opacity: 0?
| Property | Takes space | Clickable | Read by screen readers |
|---|---|---|---|
display: none |
No | No | No |
visibility: hidden |
Yes | No | No |
opacity: 0 |
Yes | Yes | Yes |
To hide something visually but keep it for screen readers, use a “visually hidden” utility class (clip plus a 1px size), not any of these.
45. What is the difference between pseudo-classes and pseudo-elements?
Pseudo-classes select elements in a state: :hover, :focus-visible, :nth-child(), :checked. Pseudo-elements style a part of an element or insert generated content: ::before, ::after, ::placeholder, ::marker. Pseudo-elements use a double colon.
46. What does :has() do?
It’s the long-awaited parent selector: it matches an element based on its descendants or following siblings. .card:has(img) styles cards that contain an image, and form:has(:invalid) styles a form with an invalid field. Combined with :focus-within, it removes a lot of JavaScript that used to toggle classes.
47. What is the difference between :focus and :focus-visible?
:focus matches any focused element, including after a mouse click. :focus-visible matches only when the browser decides a focus indicator is needed, mainly keyboard navigation. Style :focus-visible so keyboard users always see focus, and never remove outlines without a replacement.
48. What units should you use: px, em, rem, %, vw?
rem is relative to the root font size: good for font sizes and spacing, because it respects the user’s browser font setting. em is relative to the element’s own font size: useful for padding that should scale with a component’s text, but it compounds when nested. % is relative to the parent. vw/vh are relative to the viewport. px is fine for borders and fine details.
49. What is the problem with 100vh on mobile, and what replaced it?
On mobile browsers, 100vh uses the viewport height with the address bar hidden, so content gets cut off when the bar is visible. The newer units fix this: svh (small viewport), lvh (large), and dvh (dynamic, changes as the bar shows and hides).
50. What are CSS custom properties, and how do they differ from Sass variables?
Custom properties (--brand: #0ea5e9) live in the browser at runtime: they cascade, inherit, can be changed per element or media query, and can be updated with JavaScript. Sass variables are replaced at build time and don’t exist in the browser. Custom properties are what make runtime theming (dark mode) simple.
:root { --bg: white; --text: #111; }
[data-theme="dark"] { --bg: #0f172a; --text: #e2e8f0; }
body { background: var(--bg); color: var(--text); }
51. What are CSS preprocessors, and do you still need them?
Sass and Less add variables, nesting, mixins, and functions that compile to CSS. Native CSS now has custom properties, nesting, color-mix(), and @layer, so many projects no longer need a preprocessor. Mixins and loops are still nicer in Sass.
Deep dive: CSS preprocessors
52. What is the difference between resetting and normalizing CSS?
A reset removes all browser default styles so you start from zero. Normalize keeps useful defaults and only fixes inconsistencies between browsers. Modern projects usually use a small “modern reset” that does a bit of both: border-box sizing, removed default margins, and responsive images.
Deep dive: Resetting vs normalizing CSS
53. How do floats work, and how do you clear them?
A floated element moves to the left or right, and inline content wraps around it. The parent doesn’t grow to contain floats, so you clear them with display: flow-root on the parent, or a clear: both element after them. Floats are now mainly for wrapping text around images; use flexbox or grid for layout.
54. How do CSS transitions and animations differ?
Transitions animate a property between two states when it changes (on hover, or when a class toggles). Animations use @keyframes for multi-step sequences that can loop and run without a state change. Prefer animating transform and opacity: they can run on the compositor without triggering layout.
.button { transition: transform 150ms ease-out; }
.button:hover { transform: translateY(-2px); }
@keyframes spin { to { transform: rotate(360deg); } }
.spinner { animation: spin 1s linear infinite; }
55. How do you respect users who prefer reduced motion?
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
}
Motion can cause dizziness and nausea for people with vestibular disorders. Keep essential feedback (like a fade) but drop large movement, parallax, and auto-playing animation.
56. What is the difference between transform: translate() and changing top/left?
Changing top or left triggers layout on every frame. transform moves the element visually without affecting layout, so the browser can animate it on the GPU compositor. That’s the difference between a smooth 60 fps animation and a janky one.
Deep dive: Reflow vs repaint
57. What are the CSS methodologies (BEM, CSS Modules, utility-first, CSS-in-JS)?
| Approach | How it scopes styles | Trade-off |
|---|---|---|
| BEM | Naming convention (.card__title--large) |
No tooling, but relies on discipline |
| CSS Modules | Build step generates unique class names | Real scoping with plain CSS |
| Utility-first (Tailwind) | Small single-purpose classes in markup | Fast to build and consistent; verbose markup |
| CSS-in-JS | Styles defined in JavaScript | Dynamic styles; runtime libraries cost performance and complicate server rendering |
58. What is CSS nesting?
Native CSS now supports nesting rules inside rules, like Sass. & refers to the parent selector.
.card {
padding: 1rem;
&:hover { box-shadow: 0 2px 8px rgb(0 0 0 / 0.15); }
.title { font-weight: 600; }
}
59. What are container queries?
Container queries style an element based on the size of its container instead of the viewport. That makes components truly reusable: a card can switch to a horizontal layout when its column is wide, whether it’s in the main area or a sidebar.
.card-wrapper { container-type: inline-size; }
@container (min-width: 400px) {
.card { display: grid; grid-template-columns: 120px 1fr; }
}
60. How do you truncate text with an ellipsis?
/* One line */
.truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Multiple lines */
.clamp-3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
Inside a flex item, add min-width: 0 or the truncation won’t kick in, because flex items default to min-width: auto.
61. How do you load web fonts without hurting performance?
Self-host WOFF2 files, preload the one or two fonts used above the fold, subset them to the characters you need, and set font-display: swap (or optional) so text appears immediately with a fallback. Match fallback font metrics with size-adjust to reduce the layout shift when the web font loads.
62. What is the difference between em-based and pixel-based media queries?
Media queries in em scale with the user’s browser font size setting, so a user with a larger default font gets the layout designed for that effective width. Pixel breakpoints ignore that setting. Either is defensible; the important part is choosing breakpoints by where the content breaks, not by device names.
63. What does aspect-ratio do?
It sets a preferred width-to-height ratio, so aspect-ratio: 16 / 9 keeps a video or card shape as the width changes. It replaced the old padding-top percentage hack and helps prevent layout shift for media whose size isn’t known in advance.
64. How do you implement dark mode?
Define colors as custom properties, switch them with @media (prefers-color-scheme: dark) for the system preference, and add a data-theme attribute for a manual toggle saved in localStorage. Set the theme in a tiny inline script before the page paints to avoid a flash of the wrong theme. color-scheme: light dark tells the browser to adapt form controls and scrollbars too.
Deep dive: Design a theme switcher
65. Which CSS properties are expensive?
Properties that trigger layout (width, height, top, margin, font-size) are the most expensive when changed often. Paint-heavy effects like large box-shadow, filter: blur(), and backdrop-filter cost more on big areas. transform and opacity are the cheapest to animate.
Layout: Flexbox, Grid, and Responsive Design

Find in-depth explanations and practice here: CSS fundamentals in the handbook ->
Layout comes up in almost every frontend developer interview, often as “build this layout” in a live coding round. Know flexbox and grid well enough to pick the right one without thinking.
66. When do you use flexbox versus grid?
Flexbox is one-dimensional: it distributes items along a single row or column, and items size from their content outward. Grid is two-dimensional: you define rows and columns, and items are placed into them. Rule of thumb: flexbox for components (a navbar, a button group, centering), grid for page layouts and anything that must align in both directions (card grids, dashboards).
67. What do justify-content and align-items do in flexbox?
justify-content distributes items along the main axis (the row, by default): flex-start, center, space-between. align-items aligns items on the cross axis. When flex-direction: column, the axes swap, which trips people up in interviews.
68. What does flex: 1 mean?
It’s shorthand for flex-grow: 1; flex-shrink: 1; flex-basis: 0%. With a zero basis, items share the free space equally regardless of their content. flex: auto uses flex-basis: auto, so items start at their content size and share the remaining space. flex: none makes an item rigid.
69. What are flex-grow, flex-shrink, and flex-basis?
flex-basis is the starting size before free space is distributed. flex-grow is how much of the extra space an item takes, relative to its siblings. flex-shrink is how much it gives up when there isn’t enough room. A sidebar that never shrinks is flex: 0 0 240px.
70. Why does my flex item overflow instead of shrinking?
Flex items have min-width: auto by default, which means they won’t shrink below their content’s minimum size, such as a long URL or a pre block. Set min-width: 0 (or overflow: hidden) on the item to allow it to shrink.
71. What does flex-wrap do, and what is gap?
flex-wrap: wrap lets items move to new lines instead of squeezing onto one. gap sets the space between items (in flexbox and grid) without margins on the outer edges, which replaces negative-margin hacks.
72. How do you push one flex item to the end?
Give it margin-left: auto (or margin-inline-start: auto). Auto margins absorb all free space on that side. It’s the cleanest way to put a “Log out” button at the far right of a navbar.
73. How does the order property affect accessibility?
order (and flex-direction: row-reverse) changes the visual order but not the DOM order, so keyboard focus and screen readers follow the source. If the visual order differs from the reading order, users get confused. Change the HTML order when the order has meaning.
74. What does grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)) do?
It creates as many columns as fit, each at least 200px wide and stretching to share the leftover space. It’s a fully responsive card grid with no media queries.
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; }
75. What is the difference between auto-fill and auto-fit?
Both create as many tracks as fit. auto-fill keeps empty tracks, so a few items stay at their minimum size with blank columns after them. auto-fit collapses empty tracks, so the existing items stretch to fill the row. The difference only shows when there are fewer items than columns.
76. What is the fr unit?
A fraction of the free space in a grid container. grid-template-columns: 1fr 2fr gives the second column twice the leftover space of the first. Unlike percentages, fr accounts for gaps automatically.
77. What are grid template areas?
Named regions that let you draw the layout in CSS. They make page layouts readable and easy to rearrange at breakpoints.
.page {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
@media (max-width: 700px) {
.page { grid-template-columns: 1fr; grid-template-areas: "header" "main" "sidebar" "footer"; }
}
78. How do you build the holy grail layout?
Header, footer, a main column, and two sidebars, with the footer at the bottom even on short pages. With grid: three rows (auto 1fr auto) on a container with min-height: 100vh, and three columns in the middle row. It used to be a famous CSS puzzle; with grid it’s a few lines.
Practice: Handbook Layout
79. How do you keep a footer at the bottom of short pages?
body { min-height: 100dvh; display: grid; grid-template-rows: auto 1fr auto; }
The middle row (main content) takes all remaining space, pushing the footer down. The flexbox version is flex-direction: column with flex: 1 on main.
80. What is subgrid?
grid-template-columns: subgrid lets a nested grid use its parent’s tracks. The classic use is a row of cards where titles, text, and buttons line up across cards even when content lengths differ.
81. How do you build a masonry layout?
CSS columns (column-count) give a quick masonry look but order items top to bottom per column, which breaks reading order. For left-to-right order, place items with JavaScript into the shortest column, or use a grid with small row units and per-item row spans calculated from the item heights. Native CSS masonry is still being standardized.
Practice: Masonry Grid
82. What is responsive design?
Building one page that adapts to any screen size using fluid layouts, flexible images, and media or container queries, instead of separate mobile and desktop sites. Adaptive design, by contrast, serves different fixed layouts for specific breakpoints or devices.
83. What does mobile-first mean in CSS?
Write base styles for small screens, then add min-width media queries for larger ones. It keeps the mobile CSS simple (it doesn’t have to undo desktop styles), and it forces you to prioritize content.
.nav { display: none; }
@media (min-width: 768px) { .nav { display: flex; } }
84. How do you choose breakpoints?
By content: resize the page and add a breakpoint where the layout starts to look wrong. Device-based breakpoints go stale as new devices appear. Container queries reduce the number of page-level breakpoints, because components adapt to their own space.
85. What is fluid typography with clamp()?
clamp(min, preferred, max) lets a value scale with the viewport between limits, so headings grow smoothly instead of jumping at breakpoints.
h1 { font-size: clamp(1.75rem, 1rem + 3vw, 3rem); }
Include a rem part in the preferred value so text still responds to the user’s zoom and font settings.
86. What are logical properties?
Properties like margin-inline-start, padding-block, and inset-inline-end refer to the writing direction instead of physical sides. In right-to-left languages, margin-inline-start becomes the right margin automatically, so one stylesheet supports both directions.
87. How do you make a responsive table?
Options: wrap it in a container with overflow-x: auto (simplest, keeps table semantics), hide less important columns at small sizes, or turn each row into a stacked card with labels from data-* attributes. If you change the display of table elements, check that screen readers still announce it as a table.
Practice: Paginated Orders Table
88. How do you handle images in a responsive layout?
max-width: 100%; height: auto; keeps images inside their container. Use object-fit: cover to fill a fixed-ratio box without distortion, aspect-ratio to reserve space, and srcset so small screens download small files.
89. What is the difference between min-width, max-width, and width?
width sets a preferred size; min-width and max-width set limits that win over it. A common readable content column is width: 100%; max-width: 70ch; margin-inline: auto;, which shrinks on phones and caps line length on desktops.
90. What does overflow control?
What happens when content is bigger than its box: visible (default, spills out), hidden (clipped), scroll (always shows scrollbars), auto (scrollbars only when needed), and clip (clipped without creating a scroll container, so sticky children still work).
91. How do you build a sticky header that doesn’t cover anchor targets?
Use position: sticky; top: 0 on the header, and scroll-margin-top (or scroll-padding-top on the scroll container) equal to the header height, so in-page links don’t hide the heading under the header.
92. What is scroll snap?
CSS that makes a scroll container settle on specific points, which is how you build a carousel without JavaScript for the scrolling itself.
.carousel { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; }
.slide { flex: 0 0 100%; scroll-snap-align: start; }
Practice: Lean Photo Carousel
93. How do you design for touch?
Make tap targets at least about 44 by 44 CSS pixels with space between them, don’t rely on hover for essential information, use @media (hover: hover) to add hover effects only where they work, and support common gestures without making them the only way to do something.
94. How do you test responsive layouts?
Browser device mode for quick checks, real devices for touch, performance, and browser chrome quirks, and visual regression tests at a few widths in CI. Also test zoom at 200% and a larger default font size; layouts that only work at one font size aren’t responsive.
95. How would you build a responsive navigation bar?
Desktop: a flex row of links. Mobile: a menu button (a real <button> with aria-expanded and aria-controls) that shows the links in a panel. Close it on Escape and when a link is chosen, return focus to the button, and keep the links in the DOM order users expect.
Practice: Navigation
JavaScript Essentials for Frontend Interviews

Find in-depth explanations and practice here: 300+ JavaScript interview questions and answers ->
These are the 30 JavaScript questions that come up most in general frontend loops. Each one has a short answer here; the JavaScript guide linked above goes much deeper, with output puzzles and coding solutions.
96. What is the difference between var, let, and const?
var is function-scoped and hoisted with the value undefined. let and const are block-scoped and sit in the temporal dead zone until their declaration runs, so using them early throws. const prevents reassignment, not mutation: a const object can still be changed.
Deep dive: let, var, and const
97. What is the difference between == and ===?
=== compares without type conversion. == converts types first, with rules that surprise people ("" == 0 is true, null == 0 is false). Use ===; the one common exception is x == null to check for both null and undefined.
98. What are the JavaScript data types?
Seven primitives (string, number, bigint, boolean, undefined, null, symbol) and objects (including arrays and functions). Primitives are immutable and compared by value; objects are compared by reference, so {} === {} is false.
99. What is a closure?
A function that remembers the variables from the scope where it was created, even after that scope has finished running. Closures power private state, function factories, memoization, and event handlers that remember data.
function makeCounter() {
let count = 0;
return () => ++count;
}
const next = makeCounter();
next(); next();
console.log(next()); // 3
Deep dive: Closures
100. How is this determined?
By how the function is called: obj.method() sets it to obj, a plain call sets it to undefined in strict mode, new sets it to the new object, and call/apply/bind set it explicitly. Arrow functions don’t have their own this; they use the one from the surrounding scope.
Deep dive: Explain “this”
101. What is hoisting?
Declarations are registered before code runs. Function declarations are fully hoisted (callable before their line), var is hoisted as undefined, and let/const/class are hoisted but unusable until declared.
Deep dive: Hoisting
102. What is prototypal inheritance?
Every object has a hidden link to a prototype object. When a property isn’t found on the object, JavaScript looks up the prototype chain until it reaches null. class syntax is a cleaner way to set up the same prototype links.
Deep dive: Prototypal inheritance
103. How does the event loop work?
JavaScript runs one task at a time on the call stack. When the stack is empty, the event loop runs all queued microtasks (promise callbacks), then the browser may render, then the next task (a timer, an event) runs. That’s why a resolved promise’s then runs before a setTimeout(fn, 0).
setTimeout(() => console.log("timeout"), 0);
Promise.resolve().then(() => console.log("promise"));
console.log("sync");
// sync, promise, timeout
Deep dive: The event loop explained with one diagram
104. What is the difference between promises and async/await?
async/await is syntax on top of promises. An async function always returns a promise, and await pauses that function until a promise settles, letting you write async code that reads top to bottom and handle errors with try/catch.
105. What is the difference between Promise.all, allSettled, race, and any?
all resolves when every promise resolves and rejects on the first failure. allSettled waits for all and reports each result. race settles with the first promise to settle. any resolves with the first success and rejects only if all fail.
Practice: Promise Methods
106. What is event delegation?
Attaching one listener to a parent instead of one per child, and using event.target.closest() to find which child was clicked. It uses less memory and works for children added later.
Deep dive: Event delegation
107. What are event bubbling and capturing?
An event travels down from window to the target (capture phase), then back up (bubble phase). Listeners run in the bubble phase by default; pass { capture: true } to listen during capture. stopPropagation() stops the event from continuing.
Deep dive: Event propagation
108. What is the difference between preventDefault and stopPropagation?
preventDefault() cancels the browser’s default action (following a link, submitting a form). stopPropagation() stops the event from reaching other elements. They’re independent: one doesn’t do the other.
109. What are debounce and throttle?
Debounce waits until calls stop for a set time, then runs once (search-as-you-type). Throttle runs at most once per interval while calls continue (scroll or resize handlers). Both are among the most common frontend coding interview questions.
function debounce(fn, wait) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), wait);
};
}
Practice: Debounce and Throttle. Deep dive: Debounce vs throttle
110. What is the difference between null and undefined?
undefined means a value was never assigned (missing properties, missing arguments). null is an intentional “no value” that you set. typeof null is "object", a historical bug.
Deep dive: null vs undefined vs undeclared
111. What is the difference between map, filter, reduce, and forEach?
map returns a new array of transformed items, filter returns the items that pass a test, reduce folds the array into a single value, and forEach just runs a function for each item and returns undefined. Only forEach is purely for side effects.
Deep dive: forEach vs map
112. How do you copy an object, shallow versus deep?
Spread ({ ...obj }) and Object.assign make shallow copies: nested objects are still shared. structuredClone(obj) makes a deep copy and handles dates, maps, sets, and circular references, but not functions or DOM nodes.
Practice: Deep Clone
113. What are call, apply, and bind?
All three set this. call(thisArg, a, b) and apply(thisArg, [a, b]) invoke the function immediately; bind returns a new function with this (and optionally arguments) fixed.
Deep dive: Call vs apply
114. What are arrow functions, and when shouldn’t you use them?
A shorter function syntax that inherits this and arguments from the surrounding scope and can’t be used with new. Don’t use them for object methods that need this to be the object, or for event handlers where you need this to be the element.
115. What are ES modules?
The standard module system: import and export, static so bundlers can tree-shake unused code, strict mode by default, and loaded asynchronously in browsers with type="module". CommonJS (require) is Node’s older, dynamic system.
116. What do optional chaining and nullish coalescing do?
a?.b?.c returns undefined instead of throwing when a link in the chain is null or undefined. a ?? "default" uses the fallback only for null or undefined, unlike ||, which also replaces 0, "", and false.
117. What are Map and Set, and when do you use them over objects and arrays?
Map allows any key type (including objects), keeps insertion order, and has a size; use it for dictionaries with frequent additions and removals. Set stores unique values with fast has checks; use it for deduplication and membership tests.
Deep dive: Maps and sets
118. What is the difference between synchronous and asynchronous code?
Synchronous code runs line by line and blocks until each line finishes. Asynchronous code starts an operation (a request, a timer) and continues; the result is handled later through a callback, promise, or await. Because the main thread also handles rendering and input, long synchronous work freezes the page.
Deep dive: Synchronous vs asynchronous
119. How do you handle errors in async code?
Use try/catch around await, or .catch() on promise chains. Remember that fetch only rejects on network failure; an HTTP 404 or 500 resolves normally, so check response.ok.
async function getJson(url) {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
120. What is the difference between mutable and immutable updates?
A mutable update changes the existing object; an immutable update creates a new object with the change. Frameworks like React detect changes by reference, so mutating state in place often means the UI doesn’t update.
Deep dive: Mutable vs immutable
121. What are higher-order functions?
Functions that take functions as arguments or return them: map, filter, debounce, and middleware. They let you reuse behavior (timing, caching, logging) around any function.
Deep dive: Higher-order functions
122. What is currying?
Turning a function of several arguments into a chain of functions that each take one: add(1)(2)(3). It’s useful for creating specialized functions from general ones, and implementing curry is a common coding question.
Practice: Flexible Arity Curry
123. What is a polyfill?
Code that implements a newer feature for browsers that don’t support it, such as a Array.prototype.flat implementation. Transpilers (Babel, SWC) handle new syntax; polyfills handle new APIs. “Implement map, bind, or Promise.all from scratch” questions are polyfill questions.
Deep dive: Polyfills
124. What does "use strict" change?
It turns silent errors into thrown errors (assigning to undeclared variables, writing read-only properties), sets this to undefined in plain function calls, and disallows some confusing syntax. ES modules and classes are always strict.
Deep dive: “use strict”
125. How do you avoid memory leaks in a frontend app?
Remove event listeners, clear timers and intervals, close WebSockets and observers when components unmount, avoid keeping detached DOM nodes in variables, and bound your caches. Find leaks with heap snapshots in DevTools: take one, repeat an action, take another, and compare.
Deep dive: Handling memory leaks
How Browsers Work: Rendering, Networking, and Storage

Find in-depth explanations and practice here: Web request lifecycle: from URL to screen ->
These questions check whether you understand the platform underneath your framework. They come up in phone screens and again, in more depth, in system design rounds.
126. What happens when you type a URL and press Enter?
- The browser parses the URL and checks its caches (including an HSTS list that forces HTTPS).
- DNS resolves the domain to an IP address (browser cache, OS cache, then resolvers).
- It opens a connection: TCP plus a TLS handshake, or QUIC for HTTP/3.
- It sends the HTTP request; the server (or a CDN) responds with HTML.
- The browser parses HTML into the DOM, fetches CSS, scripts, and images it discovers, and builds the CSSOM.
- It combines them into the render tree, computes layout, paints, and composites layers to the screen.
In an interview, go wide first, then offer to go deep on whichever step the interviewer picks.
127. What is the critical rendering path?
The steps from receiving HTML to the first pixels: build the DOM, build the CSSOM, combine them into a render tree, layout, and paint. CSS is render-blocking, and plain scripts are parser-blocking, so optimizing the path means less critical CSS, deferred scripts, and fewer round trips before first paint.
Deep dive: Critical rendering path
128. What is the difference between the DOM and the CSSOM?
The DOM is the tree of elements built from HTML. The CSSOM is the tree of style rules built from CSS. The browser needs both to know what to show and how it looks; that’s why CSS blocks rendering.
129. What is the difference between reflow and repaint?
Reflow (layout) recalculates the size and position of elements; it happens when geometry changes and can cascade through the page. Repaint redraws pixels when only appearance changes, such as color. Compositing-only changes (transform, opacity) can skip both.
Deep dive: Reflow vs repaint
130. What is layout thrashing?
Alternating DOM writes and layout reads in a loop, which forces the browser to recalculate layout on every read. Batch all reads first, then all writes, or schedule writes in requestAnimationFrame.
// Bad: read, write, read, write... each read forces layout
items.forEach((el) => { el.style.width = el.parentNode.offsetWidth / 2 + "px"; });
// Good: read everything, then write everything
const widths = items.map((el) => el.parentNode.offsetWidth);
items.forEach((el, i) => { el.style.width = widths[i] / 2 + "px"; });
131. What does requestAnimationFrame do?
It runs a callback right before the browser’s next repaint, usually 60 times a second, and pauses in background tabs. Use it for visual updates and animations instead of setTimeout, which can fire mid-frame and cause dropped frames.
132. What is the difference between DOMContentLoaded and load?
DOMContentLoaded fires when the HTML is parsed and deferred scripts have run, without waiting for images and stylesheets to finish (unless a script is waiting on them). load fires when everything, including images, has loaded. Most app initialization belongs on DOMContentLoaded, or in a deferred script.
133. What does the browser’s main thread do?
It runs JavaScript, handles input events, calculates styles and layout, and paints. Since it does all of this, a long JavaScript task (over 50 ms) delays clicks and rendering, which hurts Interaction to Next Paint. Web Workers and splitting long tasks keep it responsive.
134. What are Web Workers, and what can’t they do?
Background threads that run JavaScript in parallel and talk to the main thread through postMessage. Use them for heavy computation: parsing large files, image processing, search indexing. They can’t access the DOM, and copying large data between threads has a cost (use transferable objects to avoid copies).
135. What is a service worker?
A script that sits between your page and the network, intercepting requests. It enables offline support, caching strategies, background sync, and push notifications. It runs on its own lifecycle (install, activate, fetch), requires HTTPS, and has no DOM access.
136. What is a Progressive Web App (PWA)?
A web app that’s installable and works offline: served over HTTPS, with a web app manifest (name, icons, display mode) and a service worker for caching. PWAs can be installed to the home screen and, depending on the platform, receive push notifications.
137. Compare cookies, localStorage, sessionStorage, and IndexedDB.
| Storage | Size | Lifetime | Sent to server | Use it for |
|---|---|---|---|---|
| Cookies | About 4 KB each | Set by expiry | Yes, with every request | Session IDs (HttpOnly), server-read preferences |
localStorage |
About 5 MB | Until cleared | No | Small non-sensitive preferences |
sessionStorage |
About 5 MB | Until the tab closes | No | Per-tab state, such as a form draft |
| IndexedDB | Large, quota-based | Until cleared | No | Offline data, large structured data, files |
Web Storage is synchronous and readable by any script on the page, so never store tokens or personal data there.
Deep dive: IndexedDB
138. What do the cookie attributes HttpOnly, Secure, and SameSite do?
HttpOnly hides the cookie from JavaScript, so an XSS attack can’t read it. Secure sends it only over HTTPS. SameSite controls whether it’s sent on cross-site requests: Strict (never), Lax (top-level navigations only, the default in modern browsers), or None (always, requires Secure). SameSite is a key CSRF defense.
139. What is the same-origin policy?
A browser rule that lets a page read responses and access data only from the same origin: scheme, host, and port must all match. https://app.example.com and https://api.example.com are different origins. It’s the foundation of web security; CORS is the controlled way to relax it.
140. What is CORS?
Cross-Origin Resource Sharing lets a server say which other origins can read its responses, through headers like Access-Control-Allow-Origin. For non-simple requests (custom headers, JSON content type, methods like PUT), the browser first sends an OPTIONS preflight to ask permission. CORS errors are enforced by the browser; the request may still reach the server.
Deep dive: CORS
141. What are the differences between HTTP/1.1, HTTP/2, and HTTP/3?
| Version | Key change | Effect on frontend |
|---|---|---|
| HTTP/1.1 | One request at a time per connection | Bundling, sprites, and domain sharding were needed |
| HTTP/2 | Multiplexing many requests over one connection, header compression | Many small files are fine; sharding hurts |
| HTTP/3 | Runs over QUIC (UDP), avoiding TCP head-of-line blocking | Faster on lossy mobile networks, quicker connection setup |
Deep dive: Web protocols cheat sheet
142. What are the common HTTP methods and status codes?
Methods: GET (read), POST (create), PUT (replace), PATCH (partial update), DELETE. Status codes: 2xx success (200, 201, 204), 3xx redirects (301 permanent, 302 temporary, 304 not modified), 4xx client errors (400, 401 unauthenticated, 403 forbidden, 404, 429 rate limited), and 5xx server errors (500, 502, 503).
143. What does idempotent mean for HTTP methods?
Making the same request several times has the same effect as making it once. GET, PUT, and DELETE are idempotent; POST isn’t, which is why double-clicking “Pay” can charge twice unless the client sends an idempotency key and the server deduplicates.
144. How does HTTP caching work?
Cache-Control tells browsers and CDNs how long a response is fresh (max-age), whether it can be shared (public/private), and whether to revalidate (no-cache) or never store it (no-store). When a cached copy is stale, the browser revalidates with ETag/If-None-Match or Last-Modified/If-Modified-Since, and a 304 response means “use what you have”.
145. What is the best caching strategy for static assets?
Put a content hash in the filename (app.3f9a2c.js) and serve it with Cache-Control: public, max-age=31536000, immutable. Serve HTML with no-cache so it always revalidates and points to the latest hashed files. A new deploy changes the hashes, so users never get stale code.
146. What is a CDN, and why use one?
A content delivery network caches your files on servers close to users, cutting latency. It also absorbs traffic spikes, terminates TLS near the user, and can run code at the edge (redirects, auth checks, personalization).
147. What is the difference between REST, GraphQL, and gRPC from a frontend view?
REST uses resource URLs and HTTP caching works naturally, but screens often need several requests or get too much data. GraphQL lets the client ask for exactly the fields it needs in one request, at the cost of more complex caching and server setup. gRPC is efficient for service-to-service calls but needs a proxy (gRPC-Web) in browsers.
Deep dive: API design
148. What are WebSockets, server-sent events, and long polling?
WebSockets are a persistent two-way connection, for chat, collaboration, and games. Server-sent events are a one-way stream from server to client over HTTP, with automatic reconnection; good for notifications and streaming AI responses. Long polling keeps a request open until there’s data, then reconnects; it’s the fallback when the others aren’t available.
Deep dive: Interface communication
149. How do you cancel a fetch request?
Pass an AbortController signal to fetch and call abort(). Use it when a component unmounts or a newer search request replaces an older one, so stale responses never overwrite fresh ones.
const controller = new AbortController();
fetch("/api/search?q=react", { signal: controller.signal }).catch((e) => {
if (e.name !== "AbortError") throw e;
});
controller.abort();
150. How do tabs of the same site communicate?
BroadcastChannel sends messages between same-origin tabs, the storage event fires in other tabs when localStorage changes, and a SharedWorker can hold shared state. A common use is logging out in every open tab at once.
Deep dive: Broadcast channels
151. How do a page and an iframe communicate safely?
With window.postMessage. Always pass a specific target origin when sending, and check event.origin when receiving, because any window can send you a message.
// Parent page
iframe.contentWindow.postMessage({ type: "theme", value: "dark" }, "https://widget.example.com");
// Inside the iframe
window.addEventListener("message", (event) => {
if (event.origin !== "https://app.example.com") return; // ignore unknown senders
if (event.data?.type === "theme") applyTheme(event.data.value);
});
152. What is the difference between client-side and server-side rendering?
Client-side rendering ships a mostly empty HTML page and builds the UI in JavaScript; simple to host, but the first paint waits for JavaScript. Server-side rendering sends ready HTML for each request, so content shows sooner and is easy to crawl, but the page must hydrate before it’s interactive and the server does more work. Static generation renders at build time for content that rarely changes.
Deep dive: SSR vs CSR
153. What is hydration?
The step where JavaScript attaches event handlers and state to server-rendered HTML so it becomes interactive. Until hydration finishes, the page looks ready but clicks may do nothing. Partial and progressive hydration, islands, and React Server Components all exist to reduce that cost.
154. What is the difference between SSG, SSR, ISR, and streaming?
| Mode | When HTML is built | Fits |
|---|---|---|
| Static generation (SSG) | At build time | Docs, marketing, blogs |
| Server rendering (SSR) | On every request | Personalized or fast-changing pages |
| Incremental regeneration (ISR) | At build, then rebuilt in the background after a time limit | Large catalogs that change occasionally |
| Streaming SSR | On request, sent in chunks as data resolves | Pages with slow data, so the shell shows early |
155. What are the browser’s main JavaScript engines and rendering engines?
Chrome and Edge use V8 and Blink, Safari uses JavaScriptCore and WebKit, and Firefox uses SpiderMonkey and Gecko. All iOS browsers have historically had to use WebKit, which is why Safari bugs affect them too.
156. How do browsers handle images, fonts, and scripts priority?
Browsers assign fetch priorities: render-blocking CSS and fonts high, scripts in the head high, images in the viewport raised once layout shows they’re visible, and lazy or offscreen images low. You can hint with fetchpriority="high" on the hero image and preload for late-discovered critical resources.
157. What is the difference between window, document, and globalThis?
window is the browser’s global object (the tab: location, history, timers). document is the loaded page’s DOM. globalThis is the standard name for the global object in any environment: window in browsers, global in Node, self in workers.
158. How does browser history and client-side routing work?
Client-side routers call history.pushState() to change the URL without a page load, listen to popstate for back and forward, and render the matching view. The server must return the app for any route, or deep links and refreshes 404. The newer Navigation API makes this simpler where supported.
159. What is the difference between sessionStorage per tab and cookies per site?
sessionStorage is scoped to one tab and origin: opening the same site in a new tab starts empty (duplicating a tab copies it). Cookies are shared by every tab of the site and sent with requests. That’s why login sessions use cookies and per-tab drafts use sessionStorage.
160. How do DevTools help you debug the browser?
Elements for the DOM and computed styles, Console for errors and evaluating code, Network for request timing, caching, and payloads, Performance for long tasks and layout work, Memory for heap snapshots, and Application for storage, service workers, and the manifest. Interviewers like hearing a concrete debugging story that used one of these.
Frameworks: React, Vue, and Angular Concepts

Find in-depth explanations and practice here: 300+ React interview questions and answers ->
Most frontend engineer interview questions about frameworks are about concepts that apply to all of them: components, state, rendering, and data flow. React gets the most examples here because it’s the most common in interviews; the React guide above goes much deeper.
161. Why use a framework instead of plain JavaScript?
Frameworks keep the UI in sync with state for you: you describe what the UI should look like for a given state, and the framework updates the DOM when state changes. They also give you components for reuse, a shared structure for teams, and an ecosystem (routing, forms, testing). For small, mostly static pages, plain JavaScript ships less code.
162. What is the difference between declarative and imperative UI?
Imperative code describes the steps: create an element, set its text, append it, remove it later. Declarative code describes the result for each state, and the framework works out the steps. Declarative UI removes a whole class of bugs where the DOM and the data drift apart.
163. What is a component?
A reusable piece of UI that takes inputs (props), may hold its own state, and returns markup. Good components do one thing, have a small and clear props interface, and don’t know about the rest of the app.
164. What is the difference between props and state?
Props are inputs passed from the parent, read-only inside the component. State is data the component owns and changes over time, and changing it triggers a re-render. If a value can be computed from props or other state, it shouldn’t be state.
Deep dive: Props and state
165. What is one-way data flow?
Data flows down from parent to child through props, and changes flow up through callbacks. Since only the owner changes a piece of state, it’s easy to trace where a value came from. Two-way binding (Angular’s [(ngModel)], Vue’s v-model) is a shortcut built on the same idea for form inputs.
166. What is the virtual DOM?
A lightweight JavaScript description of the UI. When state changes, React builds a new description, compares it with the previous one (reconciliation), and applies only the differences to the real DOM. It isn’t free; its value is letting you write declarative code with acceptable performance.
Deep dive: React reconciliation. Practice: Virtual DOM I
167. How do React, Vue, and Angular differ in how they update the UI?
| Framework | Change detection | Templates |
|---|---|---|
| React | Re-runs the component function on state change and diffs a virtual DOM | JSX (JavaScript) |
| Vue | Reactive proxies track which state each component reads and re-render only those components | HTML-based templates (JSX optional) |
| Angular | Zone-based change detection, with signals now available for fine-grained updates | HTML templates with directives |
| Svelte and Solid | Compile-time or signal-based updates to exact DOM nodes, no virtual DOM | Templates or JSX |
168. What are signals?
Reactive values that track who reads them, so when a signal changes, only the computations and DOM nodes that depend on it update. Solid, Preact, Vue (refs), Angular, and Svelte runes use the idea. React instead re-renders components and relies on memoization and the React Compiler for performance.
Practice: Observable Autorun Engine
169. What triggers a re-render in React?
A state update in the component, a re-render of its parent (unless the child is memoized and its props are unchanged), or a change in a context it reads. Props changing doesn’t trigger a render on its own; the parent re-rendering does.
Deep dive: React rendering and re-renders
170. Why do lists need keys?
Keys tell the framework which item is which between renders, so it can move existing elements instead of recreating them. Using the array index as a key breaks when items are inserted, removed, or reordered: state like an input’s text ends up attached to the wrong item. Use a stable ID from the data.
171. What are React hooks, and what are their rules?
Functions like useState and useEffect that let function components hold state and run side effects. Rules: call them at the top level (not in conditions or loops) and only from components or custom hooks, because React identifies each hook by its call order.
Deep dive: React hooks
172. What is useEffect for, and when don’t you need it?
Syncing a component with something outside React: subscriptions, timers, manual DOM work, and network requests when you’re not using a data library. You don’t need it to compute values from props or state (compute during render) or to respond to a click (do it in the event handler). Return a cleanup function to undo the effect.
173. What is the difference between controlled and uncontrolled inputs?
A controlled input’s value lives in state and updates through onChange, so the framework is the source of truth; good for validation as the user types. An uncontrolled input keeps its own value in the DOM, read through a ref or FormData on submit; simpler and faster for large forms.
Practice: Support Ticket Form
174. What is prop drilling, and how do you avoid it?
Passing props through several layers of components that don’t use them, just to reach a deep child. Fix it with component composition (pass elements as children), context for widely used values like theme or the current user, or a state library for complex shared state.
Deep dive: React context and the provider pattern
175. Where should state live?
As close to where it’s used as possible. Local state for one component, lifted to the nearest common parent when siblings share it, context for app-wide values that change rarely, a server-state cache (TanStack Query, SWR) for API data, and the URL for anything that should survive a refresh or be shareable, like filters and the current tab.
Deep dive: Local, lifted, and global state
176. What is the difference between server state and client state?
Server state is owned by the backend and cached on the client: it can go stale, needs refetching, and is shared between users. Client state is owned by the browser: UI toggles, form input, the selected tab. Mixing them in one global store is a common source of bugs and boilerplate.
Deep dive: Server state vs client state
177. When would you use Redux, Zustand, or context?
Context for low-frequency values (theme, locale, auth). Zustand or Jotai for shared client state with little boilerplate. Redux Toolkit for large apps that benefit from strict patterns, middleware, and time-travel debugging. None of them for server data; use a server-state library.
178. What are higher-order components and render props?
Older patterns for sharing logic. A higher-order component wraps a component and returns an enhanced one (withAuth(Page)); a render prop passes a function that returns UI. Custom hooks replaced most uses because they share logic without extra wrapper components.
Deep dive: Higher-order components
179. What are the component lifecycle phases?
Mount (created and inserted), update (re-rendered due to new props or state), and unmount (removed). In class components these map to methods like componentDidMount; in function components, useEffect with its cleanup covers mount, update, and unmount.
Deep dive: Lifecycle methods
180. How do you optimize a slow React app?
Measure first with the React Profiler. Then: move state down so fewer components re-render, split context so updates don’t reach every consumer, memoize expensive components and values, virtualize long lists, lazy-load routes and heavy components, and use transitions to keep input responsive during big updates.
Deep dive: Avoiding context re-render pitfalls
181. What are React Server Components?
Components that run only on the server and send rendered output, not JavaScript, to the browser. They can read databases and files directly and keep large dependencies off the client. Client Components (marked with "use client") handle interactivity. The result is less JavaScript and fewer client-side data waterfalls.
182. What are error boundaries?
Components that catch errors thrown while rendering their children and show a fallback UI instead of a blank page. They don’t catch errors in event handlers or async code, which you handle with try/catch. Place them around routes and independent widgets so one failure doesn’t take down the whole app.
183. What is code splitting in a framework app?
Breaking the bundle into chunks that load on demand, usually per route and for heavy components like editors or charts. In React, lazy(() => import("./Editor")) with <Suspense> shows a fallback while the chunk loads.
Deep dive: Code splitting and lazy loading
184. What are design patterns like MVVM in frontend apps?
MVVM separates the Model (data and business logic), the View (rendering), and the ViewModel (state and actions shaped for the view). In React, a custom hook often acts as the ViewModel, so components stay presentational and logic is testable without rendering.
Deep dive: MVVM design pattern in React
185. How do you choose a framework for a new project?
Weigh team experience, hiring, ecosystem maturity, rendering needs (SSR and SEO), performance needs, and how long the project will live. A strong interview answer names the constraints first and then the choice, for example: “content-heavy and SEO-critical, team knows React, so Next.js with mostly Server Components”.
Web Performance and Core Web Vitals

Find in-depth explanations and practice here: Core Web Vitals ->
Performance questions test whether you measure before optimizing and whether you know which fix matches which problem. Always connect a technique to the metric it improves.
186. What are the Core Web Vitals?
| Metric | Measures | Good threshold |
|---|---|---|
| Largest Contentful Paint (LCP) | When the main content appears | 2.5 s or less |
| Interaction to Next Paint (INP) | How quickly the page responds to interactions | 200 ms or less |
| Cumulative Layout Shift (CLS) | How much content jumps around | 0.1 or less |
Google measures them at the 75th percentile of real users. INP replaced First Input Delay in 2024. See web.dev’s Web Vitals guide for the official definitions.
187. How do you improve LCP?
Find the LCP element first (usually a hero image or heading). Then: serve HTML fast (CDN, caching, fewer redirects), make the LCP image discoverable in the HTML with fetchpriority="high" instead of lazy-loading it or setting it from JavaScript, compress and size images properly, and remove render-blocking CSS and scripts.
188. How do you improve INP?
Break up long tasks so the main thread can respond, do less work in event handlers (show feedback first, then do the heavy work), avoid large re-renders on each keystroke, debounce expensive handlers, and move heavy computation to a Web Worker. Look for long tasks in the Performance panel during the slow interaction.
Deep dive: Debugging INP in React
189. How do you fix layout shift (CLS)?
Set width and height (or aspect-ratio) on images, videos, and embeds; reserve space for ads and late-loading banners; don’t insert content above existing content unless the user asked for it; and reduce font swap shifts with matched fallback fonts. Animate with transform rather than properties that move other content.
190. What other performance metrics matter?
Time to First Byte (server and network speed), First Contentful Paint (when anything appears), Total Blocking Time (a lab proxy for responsiveness), and bundle size. For single-page apps, also track route transition time and memory over a long session.
191. What is the difference between lab data and field data?
Lab data (Lighthouse, WebPageTest) comes from a controlled test run: repeatable and good for debugging. Field data (Chrome UX Report, your own real-user monitoring) comes from real users on real devices and networks: what actually matters, but noisier. A page can score 100 in Lighthouse and still have poor field INP.
192. How do you reduce JavaScript bundle size?
Analyze the bundle first (a bundle visualizer). Then split code by route, lazy-load heavy components, remove or replace large dependencies, import only what you use so tree shaking works, avoid shipping polyfills to modern browsers, and move rendering to the server where possible.
193. What is tree shaking?
Removing exports that are never imported, done by the bundler at build time. It relies on static ES module syntax, and it fails when modules have side effects at import time or when you import a whole library through a CommonJS entry point.
194. What is lazy loading?
Loading resources only when they’re needed: images below the fold (loading="lazy"), route chunks on navigation, and heavy widgets on interaction or when they scroll into view (using IntersectionObserver). It shrinks the initial load, but lazy-loading things that are needed immediately makes the page slower.
195. How do you optimize images?
Use modern formats (AVIF or WebP with fallbacks), serve the right size with srcset, compress, lazy-load offscreen images, set dimensions to avoid layout shift, and use an image CDN to resize on the fly. Images are often the largest bytes on a page, so this is usually the quickest win.
Deep dive: Image optimization strategies and Image caching strategies
196. What is list virtualization?
Rendering only the rows visible in the viewport (plus a small buffer) instead of thousands of DOM nodes, and swapping content as the user scrolls. It keeps long lists, tables, and feeds fast. Variable row heights need measuring and caching sizes as rows render.
Deep dive: List virtualization and Virtualizing variable-height lists
197. How do you make infinite scroll performant?
Load the next page with an IntersectionObserver on a sentinel element near the bottom, cancel or ignore stale requests, virtualize once the list gets long, and keep the scroll position when the user navigates back. Provide a “Load more” button as a fallback for keyboard users and for reaching the footer.
Practice: Infinite Scrolling News Feed
198. What is the difference between prefetching data and prefetching code?
Prefetching code loads the JavaScript chunk for a route the user will probably visit (on link hover or when the link is visible). Prefetching data starts the API request early, so the next screen has its data when it renders. Doing both makes navigations feel instant; doing it for everything wastes bandwidth.
199. What are request waterfalls, and how do you avoid them?
A waterfall is when one request can’t start until another finishes: the HTML loads JavaScript, which renders a component, which fetches data, which renders a child, which fetches more. Fix it by fetching in parallel at the route level, rendering on the server, and preloading critical resources.
Deep dive: Data fetching strategies
200. How does compression help, and what’s the difference between gzip and Brotli?
Text assets (HTML, CSS, JavaScript, JSON) compress very well. Brotli usually produces smaller files than gzip for the same content, and all modern browsers support it. Pre-compress static files at build time at a high level; compress dynamic responses at a lower level to save server CPU.
201. What is critical CSS?
The minimum CSS needed to render the visible part of the page, inlined in the HTML head so the first paint doesn’t wait for the full stylesheet. The rest loads without blocking. It’s most useful for content pages; with good caching and small CSS, the gain is smaller.
202. How do you measure performance in code?
The Performance API: performance.now() for precise timing, performance.mark() and measure() for named spans that show up in DevTools, and PerformanceObserver for long tasks, layout shifts, and paint timings. The web-vitals library reports Core Web Vitals from real users to your analytics.
203. How do you profile a slow interaction?
Record it in the DevTools Performance panel with CPU throttling on, find the long task, and read the flame chart to see which functions took the time. In React apps, add the React Profiler to see which components rendered and why. Fix the biggest cost, then record again to confirm.
204. What causes jank during scrolling?
Expensive scroll handlers running on every event, layout thrashing, heavy paint effects (large shadows and blurs), and too many DOM nodes. Use passive listeners, IntersectionObserver instead of scroll math, transform-based animation, and virtualization.
205. What does will-change do?
It hints that an element is about to change a property (like transform), so the browser can promote it to its own layer ahead of time. Use it sparingly, only right before an animation: every layer uses GPU memory, and applying it everywhere makes things slower.
206. What are resource hints, and when do they help?
preconnect warms up connections to critical third-party origins (font or image CDNs), dns-prefetch is a cheaper fallback, preload fetches late-discovered critical resources (fonts referenced in CSS), and modulepreload preloads ES modules and their dependencies. Each one costs bandwidth, so add them only for resources you know are critical.
207. How do third-party scripts affect performance?
Analytics, ads, chat widgets, and tag managers often run large amounts of JavaScript on the main thread and add connections. Load them with async or defer, delay non-critical ones until after load or interaction, use facades (a static image of a video player until clicked), and audit them regularly.
208. What is a performance budget?
Limits the team agrees to, such as “under 170 KB of compressed JavaScript on the critical path” or “LCP under 2.5 s on a mid-range phone”, checked in CI so regressions fail the build. Budgets turn performance from a one-time project into an ongoing standard.
209. How do you speed up a slow single-page app’s first load?
Server-render or statically generate the first view, split the bundle so the first route only loads what it needs, inline critical CSS, preload the main data request, and cache aggressively with a service worker for repeat visits. Measure with field data on real mobile devices, not only a fast laptop.
Deep dive: Frontend performance optimizations
210. How would you explain a performance win in an interview?
Give the starting metric, how you found the cause, what you changed, and the result with a number. A hypothetical example of the shape: “INP on the search page was 450 ms at p75; profiling showed every keystroke re-rendered a 2,000-row table; I moved the filter into a transition and virtualized the table; INP dropped to 120 ms.” Numbers make the story credible.
Accessibility Interview Questions

Find in-depth explanations and practice here: Web accessibility ->
Accessibility used to be a bonus topic. Now many companies ask about it directly and check it in every UI coding round: can a keyboard user operate your component, and does a screen reader announce it correctly? For more, see the accessibility interview questions guide.
211. What is web accessibility, and why does it matter?
Building sites that people with disabilities can use: blind and low-vision users, deaf users, people who can’t use a mouse, and people with cognitive disabilities. It matters because it’s a large share of users, it’s a legal requirement in many places, and accessible sites are usually more usable for everyone.
212. What is WCAG?
The Web Content Accessibility Guidelines, the standard most laws and companies reference. Its criteria are grouped under four principles (perceivable, operable, understandable, robust) and three levels: A, AA, and AAA. Most organizations target WCAG 2.1 or 2.2 at level AA.
213. What is ARIA, and what is the first rule of ARIA?
Accessible Rich Internet Applications: attributes that add roles, states, and properties for assistive technology (role="tab", aria-expanded, aria-label). The first rule: don’t use ARIA if a native element does the job. A <button> beats <div role="button">, because ARIA changes what’s announced but adds no behavior.
Deep dive: ARIA roles and attributes
214. What is the difference between aria-label, aria-labelledby, and aria-describedby?
aria-label gives an element a name directly, for icon-only buttons. aria-labelledby points to another element whose text becomes the name, such as a dialog pointing to its heading. aria-describedby adds extra description, such as a hint or an error message under an input, read after the name.
215. How do you make a site keyboard accessible?
Every interactive element must be reachable with Tab, operable with Enter or Space (and arrow keys for composite widgets like tabs and menus), and show a visible focus indicator. Focus order should follow the visual order, and nothing should trap focus except a modal, which must release it on close.
216. What does tabindex do?
tabindex="0" makes an element focusable in the normal tab order. tabindex="-1" makes it focusable from JavaScript but skips it in the tab order, useful for moving focus to a heading or a dialog. Positive values force a custom order and almost always cause confusion; avoid them.
217. How do you build an accessible modal dialog?
- Use
<dialog>withshowModal(), orrole="dialog"witharia-modal="true"and a label. - Move focus into the dialog on open and keep it there while open.
- Close on Escape and return focus to the element that opened it.
- Make the background inert so screen readers and Tab can’t reach it.
Deep dive: Design an accessible dialog. Practice: Unsaved Changes Modal
218. How do you build accessible tabs?
A container with role="tablist", buttons with role="tab" and aria-selected, and panels with role="tabpanel" linked by aria-controls and aria-labelledby. Arrow keys move between tabs; only the active tab is in the tab order (roving tabindex).
Practice: Accessible Tabs and Vertical Keyboard Tabs
219. What is roving tabindex?
A technique for composite widgets (tabs, toolbars, menus, grids): only the current item has tabindex="0", the rest have -1, and arrow keys move focus and update the values. One Tab stop for the whole widget keeps keyboard navigation fast.
220. How do you build an accessible accordion?
Each header is a <button> inside a heading, with aria-expanded and aria-controls pointing to its panel. Native <details>/<summary> gives you this behavior for free when you don’t need custom animation or “one open at a time” logic.
Practice: Accessible FAQ Accordion
221. How do you announce dynamic changes to screen readers?
Use a live region: an element with aria-live="polite" (announced when the user is idle) or role="alert" (announced immediately) that exists in the DOM before you change its text. Use it for search result counts, form errors after submit, and toast messages.
222. What is the minimum color contrast?
WCAG AA requires 4.5:1 for normal text and 3:1 for large text (about 24px, or 19px bold) and for UI components like input borders and focus indicators. Don’t rely on color alone to convey meaning: pair red error text with an icon or a message.
223. What is a skip link?
A link at the very top of the page, visible on focus, that jumps to the main content: <a href="#main" class="skip-link">Skip to content</a>. It saves keyboard users from tabbing through the whole navigation on every page.
224. How do you make forms accessible?
Every input has a visible label, related inputs are grouped with fieldset and legend, required fields are marked in text (not only with color or an asterisk), errors are linked with aria-describedby and aria-invalid, and on submit, focus moves to the first error or an error summary.
225. How do you test accessibility?
Automated tools (axe, Lighthouse, eslint-plugin-jsx-a11y) catch some issues, such as missing labels and low contrast, but not most. Add manual checks: navigate with only the keyboard, use a screen reader (VoiceOver, NVDA), zoom to 200%, and turn on reduced motion. Testing Library’s role-based queries also push your tests toward accessible markup.
226. How do screen readers navigate a page?
By headings, landmarks, links, form controls, and tables, as well as reading line by line. That’s why heading structure, landmarks, and descriptive link text matter: a list of ten “Read more” links is useless out of context.
227. What makes a good focus indicator?
Visible against every background it appears on (3:1 contrast with its surroundings), clearly larger than a hairline, and shown at least for keyboard focus via :focus-visible. Removing outline without a replacement is one of the most common accessibility failures.
228. How do you make a custom select or combobox accessible?
It’s one of the hardest widgets: the input needs role="combobox", aria-expanded, and aria-controls; the list needs role="listbox" with role="option" items; the highlighted option is tracked with aria-activedescendant; and arrow keys, Enter, and Escape must work. Use a native <select> or a tested library unless you must build it.
Deep dive: Design an autocomplete
229. How do you handle focus in a single-page app after navigation?
Full page loads reset focus to the top; client-side navigations don’t, so screen reader users may not know the page changed. After a route change, move focus to the new page’s main heading (with tabindex="-1") or announce the new page title in a live region, and update document.title.
230. What does “accessible name” mean, and how is it computed?
The name assistive technology announces for an element. Browsers compute it in priority order: aria-labelledby, then aria-label, then native labeling (the <label>, the alt text, or the element’s text content), then title as a last resort. You can see it in the Accessibility pane of DevTools.
Frontend Security: XSS, CSRF, CSP, and CORS

Find in-depth explanations and practice here: Frontend security best practices ->
Security questions check that you know the common attacks and the browser features that stop them. You don’t need to be a security engineer, but you should never ship the classic mistakes.
231. What is cross-site scripting (XSS)?
An attack where malicious script runs in your page, in your users’ sessions. Stored XSS saves the payload in your database (a comment); reflected XSS comes from the URL; DOM-based XSS happens when client code writes untrusted data into the DOM. The script can steal data, act as the user, or change the page.
Deep dive: XSS vs CORS
232. How do you prevent XSS?
- Insert untrusted data as text (
textContent, framework templates), never as HTML. - Avoid
innerHTML,dangerouslySetInnerHTML, andv-htmlwith user data; if you must render user HTML, sanitize it with an allowlist sanitizer like DOMPurify. - Validate URLs before putting them in
hreforsrc: blockjavascript:URLs. - Add a Content Security Policy as a second line of defense.
Practice: Allowlist HTML Sanitizer
233. Do frameworks like React prevent XSS?
Mostly: React escapes values in JSX, so {userInput} renders as text. The gaps are dangerouslySetInnerHTML, user-controlled href values (javascript: URLs), spreading user-controlled props onto elements, and server-rendered data injected into a script tag without escaping.
234. What is cross-site request forgery (CSRF)?
An attack where another site makes the user’s browser send a request to your site, and the browser automatically attaches the user’s cookies, so the request runs as them. Defenses: SameSite=Lax or Strict cookies, CSRF tokens on state-changing requests, checking the Origin header, and never changing state on GET.
235. What is a Content Security Policy (CSP)?
A response header that tells the browser which sources of scripts, styles, images, and connections are allowed. A strict CSP with nonces blocks inline scripts that an attacker injects, even if your escaping fails somewhere.
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-r4nd0m'; object-src 'none'; frame-ancestors 'none'; base-uri 'none'
236. What is clickjacking, and how do you prevent it?
An attacker loads your site in an invisible iframe and tricks users into clicking buttons on it. Prevent it with the CSP frame-ancestors directive (or the older X-Frame-Options: DENY), which controls who can frame your pages.
237. Where should you store authentication tokens in the browser?
The safest common choice is an HttpOnly, Secure, SameSite cookie: JavaScript can’t read it, so XSS can’t steal it, though you still need CSRF protection. Tokens in localStorage are readable by any script on the page. If you use bearer tokens, keep access tokens short-lived and in memory, with refresh handled through an HttpOnly cookie.
238. Is CORS a security feature?
CORS relaxes the same-origin policy; it doesn’t add protection on its own. A misconfigured CORS policy (reflecting any origin with credentials allowed) is a vulnerability. And CORS doesn’t stop requests from reaching your server, so server-side authorization and CSRF protection are still required.
239. What security headers should every site send?
| Header | Purpose |
|---|---|
Content-Security-Policy |
Restricts script and resource sources; limits XSS damage |
Strict-Transport-Security |
Forces HTTPS on future visits |
X-Content-Type-Options: nosniff |
Stops the browser from guessing content types |
Referrer-Policy |
Limits how much of the URL is sent to other sites |
Permissions-Policy |
Disables features like camera or geolocation you don’t use |
240. What is Subresource Integrity (SRI)?
An integrity attribute with a hash on a script or stylesheet tag. If a CDN serves a modified file, the hash won’t match and the browser refuses to run it. It protects you when a third-party CDN is compromised.
241. Why should secrets never be in frontend code?
Everything shipped to the browser is public: bundles, environment variables baked in at build time, and source maps. API keys for paid services, database credentials, and signing secrets must stay on the server. Frontend code calls your backend, which holds the secret.
242. What are the risks of eval and new Function?
They run strings as code, so any untrusted data that reaches them becomes code execution. They also block engine optimizations and are disallowed by strict CSP. There’s almost always a safer option: JSON.parse for data, or a lookup table for dynamic behavior.
243. What is a supply chain attack in the frontend?
Malicious code that enters through a dependency: a compromised npm package, a typosquatted package name, or a hijacked third-party script. Defenses: lockfiles, reviewing new dependencies, automated vulnerability scanning, limiting install scripts, SRI for CDN scripts, and CSP to limit what injected code can reach.
244. What is prototype pollution?
An attack where untrusted input sets properties on Object.prototype (via keys like __proto__ in a deep merge), affecting every object in the app. Prevent it by rejecting those keys in merge and set-by-path utilities, using Object.create(null) or Map for dictionaries, and validating input shapes.
245. How do you secure an AI or chat feature in the frontend?
Treat model output as untrusted input: render it as text or sanitized Markdown, never as raw HTML. Keep API keys on the server, rate-limit and authenticate requests through your backend, and don’t let model output trigger actions without validation.
Deep dive: Build ChatGPT frontend system design
Testing, Tooling, and Git

Find in-depth explanations and practice here: Unit tests vs functional and integration tests ->
These questions come up more for mid-level and senior roles. Interviewers want to know you ship code that’s tested and that you understand the build pipeline you rely on.
246. What are unit, integration, and end-to-end tests?
| Type | Tests | Tools | Trade-off |
|---|---|---|---|
| Unit | One function or component in isolation | Vitest, Jest | Fast and precise, but can miss integration bugs |
| Integration | Several units together, like a form with validation and an API mock | Testing Library, MSW | The best confidence for the cost in most UIs |
| End-to-end | The real app in a real browser | Playwright, Cypress | Highest confidence; slow and can be flaky |
247. What is the guiding principle of Testing Library?
“The more your tests resemble the way your software is used, the more confidence they can give you.” Query by role and label text (getByRole("button", { name: "Save" })), interact like a user, and assert on what’s visible, not on component internals or state.
248. What makes a good frontend test?
It tests behavior the user cares about, fails for one clear reason, doesn’t depend on implementation details (class names, internal state), mocks only at the boundaries (network, time), and runs fast and the same every time. A test that breaks on every refactor without catching bugs costs more than it saves.
249. How do you test components that fetch data?
Mock the network, not your fetching code: Mock Service Worker intercepts requests and returns fixture data, so the component runs its real data path. Test the loading, success, empty, and error states, and use findBy queries to wait for async updates.
250. How do you deal with flaky tests?
Find the cause instead of adding retries: usually real timers, animations, shared state between tests, test order dependence, or waiting on arbitrary timeouts. Use fake timers, wait for specific UI conditions, reset state between tests, and quarantine a flaky test with a ticket rather than letting the team learn to ignore failures.
Practice: Fake Timer
251. What are snapshot tests, and when are they useful?
Tests that save rendered output and fail when it changes. They catch unintended changes in small, stable outputs (a serializer, an error message), but large component snapshots get approved without reading and become noise. Visual regression tools (screenshot comparisons) are a better fit for catching styling changes.
252. What does a bundler do?
It starts from entry files, follows imports to build a dependency graph, transforms code (TypeScript, JSX, modern syntax), removes unused code, splits output into chunks, minifies, and writes hashed files for caching. Webpack, Rollup, esbuild, and Rspack are bundlers; Vite uses esbuild and Rollup-based tooling under the hood.
253. Why is Vite fast in development?
It doesn’t bundle your app in development. It serves source files as native ES modules and transforms each file on request, so startup doesn’t grow with app size, and hot module replacement updates only the edited module. Dependencies are pre-bundled once with esbuild.
254. What is the difference between a transpiler and a bundler?
A transpiler (Babel, SWC, the TypeScript compiler) converts code from one form to another, file by file: TypeScript to JavaScript, JSX to function calls, new syntax to older syntax. A bundler combines many modules into optimized output files. Most build tools do both.
255. What is hot module replacement (HMR)?
Swapping an edited module into the running app without a full reload, keeping state like form input and scroll position. React Fast Refresh builds on it to keep component state across edits.
256. What are source maps?
Files that map minified, bundled code back to the original source, so stack traces and debuggers show your real file and line. Upload them to your error monitoring tool instead of serving them publicly if you don’t want your source readable.
257. Why use TypeScript in a frontend codebase?
It catches type errors before runtime, makes refactoring large codebases safer, documents component props and API shapes, and gives better editor autocomplete. The costs are build setup and learning curve. Types disappear at runtime, so validate external data (API responses, user input) with a schema library like Zod.
258. What do linters and formatters do?
Formatters (Prettier) enforce consistent style so reviews never argue about it. Linters (ESLint) catch likely bugs: unused variables, missing hook dependencies, floating promises, and accessibility mistakes. Run both in the editor and in CI.
Deep dive: Code quality with linting tools
259. What is the difference between git merge and git rebase?
Merge combines branches with a merge commit and keeps the full history as it happened. Rebase replays your commits on top of another branch, giving a linear history. Rebase your own local branch to update it; don’t rebase commits others have already pulled, because it rewrites history.
260. What is the difference between git fetch and git pull, and how do you resolve a merge conflict?
git fetch downloads remote changes without changing your branch; git pull fetches and then merges (or rebases). To resolve a conflict: open the conflicting files, choose or combine the changes between the conflict markers, run the tests, then git add the files and continue the merge or rebase.
Frontend Coding Interview Questions: UI Components

Find in-depth explanations and practice here: React coding questions and JavaScript coding questions ->
In a UI coding round you build a working component in 30 to 60 minutes, usually in React or plain JavaScript. These frontend coding interview questions are the components that keep coming up. For each one: what to clarify, the key idea, and where to build it with tests.
261. How do you approach a UI coding round?
- Clarify: inputs, required features, edge cases, and whether accessibility and styling matter (they usually do).
- Model state: write down the minimal state before any JSX. Most bugs come from duplicated or derived state.
- Build the happy path end to end, then add edge cases: empty, loading, error, very long content.
- Make it accessible: semantic elements, keyboard support, labels.
- Talk through trade-offs and what you’d add with more time: tests, performance, extracting a hook.
262. Build an autocomplete (typeahead) search.
Clarify: minimum characters, debounce delay, how many results, and keyboard support. Key ideas: debounce the input, cancel stale requests so old responses can’t overwrite new ones, cache results per query, support arrow keys, Enter, and Escape, and highlight the matching text.
function useSearch(query) {
const [results, setResults] = useState([]);
useEffect(() => {
if (!query) { setResults([]); return; }
const controller = new AbortController();
const timer = setTimeout(() => {
fetch(`/api/search?q=${encodeURIComponent(query)}`, { signal: controller.signal })
.then((res) => res.json())
.then(setResults)
.catch((e) => { if (e.name !== "AbortError") console.error(e); });
}, 250);
return () => { clearTimeout(timer); controller.abort(); }; // debounce + cancel stale request
}, [query]);
return results;
}
Practice: Autocomplete Search List and Auto Suggest Search List. Deep dive: Design an autocomplete
263. Build a star rating component.
Clarify: number of stars, half stars, read-only mode. Key ideas: separate the saved value from the hover preview, use real buttons (or radio inputs) so it works with the keyboard, and give each star an accessible name.
function StarRating({ max = 5, value, onChange }) {
const [hover, setHover] = useState(0);
return (
<div role="radiogroup" aria-label="Rating" onMouseLeave={() => setHover(0)}>
{Array.from({ length: max }, (_, i) => i + 1).map((n) => (
<button key={n} type="button" role="radio" aria-checked={value === n}
aria-label={`${n} star${n > 1 ? "s" : ""}`}
onClick={() => onChange(n)} onMouseEnter={() => setHover(n)}>
{n <= (hover || value) ? "★" : "☆"}
</button>
))}
</div>
);
}
Practice: Star Rating System
264. Build a tabs component.
State is just the active tab ID. Render tab buttons from data, show only the active panel, and wire up role="tablist"/tab/tabpanel with arrow-key navigation. Ask whether inactive panels should stay mounted (keeps their state) or unmount (less memory).
Practice: Tabs and Accessible Tabs
265. Build an accordion.
Clarify: can several sections be open at once? Store a Set of open IDs (multiple) or a single ID (one at a time). Each header is a button with aria-expanded controlling its panel. Animating height smoothly is a good follow-up: grid-template-rows: 0fr to 1fr works without measuring.
Practice: Accessible FAQ Accordion and Firmware Changelog Accordion
266. Build a modal dialog.
Render it in a portal (or use native <dialog>), trap focus inside, close on Escape and backdrop click, return focus to the trigger, and lock background scroll. A common follow-up is a confirm step that blocks closing when there are unsaved changes.
Practice: Unsaved Changes Modal. Deep dive: Design an accessible dialog
267. Build a progress bar.
Clamp the value between 0 and 100, animate width changes with a CSS transition (or transform: scaleX() for smoother animation), and expose role="progressbar" with aria-valuenow, aria-valuemin, and aria-valuemax. Follow-ups: several bars filling one after another, or a limit on how many fill at once.
Practice: Progress Bar
268. Build a to-do app.
State: an array of { id, text, done } plus a filter (all, active, done). Derive the visible list from those during render; don’t store it separately. Use a form so Enter adds an item, generate stable IDs, and update immutably. Follow-ups: editing, persistence in localStorage, and drag to reorder.
Practice: To-do App
269. Build an image carousel.
State is the current index; next and previous wrap around with modulo. Preload neighboring images, support keyboard arrows and swipe, pause autoplay on hover and focus, and provide a pause button. CSS scroll snap can handle the scrolling itself.
Practice: Image Slider and Lean Photo Carousel. Deep dive: Design a photo slider
270. Build an infinite scrolling feed.
Keep items, a cursor for the next page, and loading and error states. An IntersectionObserver on a sentinel element triggers the next fetch; guard against duplicate fetches while one is in flight. Mention virtualization for long sessions and restoring scroll position on back navigation.
Practice: Infinite Scrolling News Feed. Deep dive: Design a news feed
271. Build a sortable, paginated data table.
State: sort column and direction, current page, and page size. Derive the rows: sort a copy (never mutate props), then slice for the page. Reset to page 1 when sorting or filtering changes. Use aria-sort on the sorted header. For large data, sorting and pagination move to the server.
Practice: Multi-Sort Data Table, Paginated Orders Table, and Sortable Race Results
272. Build nested comments.
Render the tree with a recursive component. For updates (reply, edit, delete), a normalized shape ({ byId, childIds }) makes changes simple and avoids deep immutable updates. Discuss collapsing threads and limiting indentation depth on mobile.
Practice: Nested Comments I and Nested Comments II
273. Build a file explorer tree.
Recursive rendering of folders and files, a Set of expanded folder IDs, and sorting folders before files. For accessibility, use role="tree" and treeitem with aria-expanded, and arrow keys to move and expand.
Practice: File Navigation and Accessible File Tree
274. Build hierarchical (nested) checkboxes.
Checking a parent checks all descendants; a parent is checked when all children are checked and indeterminate when some are. Store only the leaf selections and derive parent states, so they can’t get out of sync. The indeterminate state can only be set from JavaScript: input.indeterminate = true.
function nodeState(node, checkedLeaves) {
if (!node.children) return checkedLeaves.has(node.id) ? "checked" : "unchecked";
const states = node.children.map((child) => nodeState(child, checkedLeaves));
if (states.every((s) => s === "checked")) return "checked";
if (states.every((s) => s === "unchecked")) return "unchecked";
return "indeterminate";
}
const tree = { id: "all", children: [{ id: "a" }, { id: "b" }] };
console.log(nodeState(tree, new Set(["a"]))); // "indeterminate"
Practice: Hierarchical Checkbox
275. Build tic-tac-toe.
State: a 9-cell array and whose turn it is (or derive the turn from the number of moves). Check the winner against the 8 winning lines after each move, and disable moves after a win. Follow-ups: an N by N board, move history with time travel, and a computer opponent.
const LINES = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]];
function getWinner(board) {
for (const [a, b, c] of LINES) {
if (board[a] && board[a] === board[b] && board[a] === board[c]) return board[a];
}
return board.every(Boolean) ? "draw" : null;
}
console.log(getWinner(["X", "X", "X", null, "O", "O", null, null, null])); // "X"
Practice: Tic Tac Toe
276. Build a signup form with validation.
Validate on blur and on submit (not on every keystroke before the user finishes), show errors next to fields and linked with aria-describedby, disable the submit button only while submitting, and move focus to the first error. Keep validation rules in one schema so the client and server can share them.
Practice: Signup Form and Support Ticket Form
277. Build a stopwatch or countdown timer.
Don’t count interval ticks: intervals drift and pause in background tabs. Store the start timestamp and accumulated time, and compute the display as accumulated + (Date.now() - startedAt) on each tick. Clear the interval on pause and unmount. Laps are snapshots of the elapsed time.
Practice: Lap Split Stopwatch and Stoppable Repeat Timer
278. Build a traffic light.
It’s a state machine: each state knows its duration and next state. Driving it with chained setTimeout calls (not a fixed interval) supports different durations per light.
const NEXT = { green: "yellow", yellow: "red", red: "green" };
const DURATION = { green: 3000, yellow: 1000, red: 4000 };
function startLight(onChange, state = "green") {
let timer;
const show = (s) => {
onChange(s);
timer = setTimeout(() => show(NEXT[s]), DURATION[s]);
};
show(state);
return () => clearTimeout(timer); // stop
}
Practice: Crosswalk Traffic Signal
279. Build a poll or voting widget.
Show options, record one vote, then reveal results as percentages with bars. Use optimistic updates (show the vote immediately, roll back on error), prevent double voting, and round percentages so they still add up to 100.
Practice: Poll Results Reveal. Deep dive: Design a voting widget
280. Build a memory (flip pairs) game.
Shuffle pairs with Fisher-Yates, track flipped and matched card IDs, and lock input while two unmatched cards are showing, before flipping them back after a short delay. Clean up that timeout on unmount or restart.
Practice: Flip Pairs Game
281. Build a Wordle-style word guessing game.
The tricky part is scoring repeated letters. Mark exact matches first, count the remaining letters in the answer, then mark “present” only while that letter’s count lasts.
function scoreGuess(guess, answer) {
const result = Array(guess.length).fill("absent");
const remaining = {};
for (let i = 0; i < guess.length; i++) {
if (guess[i] === answer[i]) result[i] = "correct";
else remaining[answer[i]] = (remaining[answer[i]] || 0) + 1;
}
for (let i = 0; i < guess.length; i++) {
if (result[i] !== "correct" && remaining[guess[i]] > 0) {
result[i] = "present";
remaining[guess[i]]--;
}
}
return result;
}
console.log(scoreGuess("speed", "abide")); // ["absent", "absent", "present", "absent", "present"]
Practice: Word Guess Grid
282. Highlight search matches in text.
Escape the query for use in a regular expression, split the text on it with a capturing group, and render matching parts in <mark> as text. Never build HTML strings with user input; that’s an XSS hole.
function highlightParts(text, query) {
if (!query) return [{ text, match: false }];
const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
return text
.split(new RegExp(`(${escaped})`, "gi"))
.filter(Boolean)
.map((part) => ({ text: part, match: part.toLowerCase() === query.toLowerCase() }));
}
console.log(highlightParts("React and react-dom", "react").map((p) => p.match));
// [true, false, true, false]
Practice: Highlight Matches
283. Add undo and redo to a component.
Keep three pieces of state: past, present, and future. A new change pushes the present onto past and clears future; undo and redo move values between the stacks. Cap the history length for memory.
function createHistory(initial) {
const past = [];
const future = [];
let present = initial;
return {
get: () => present,
set(next) { past.push(present); present = next; future.length = 0; },
undo() { if (past.length) { future.push(present); present = past.pop(); } },
redo() { if (future.length) { past.push(present); present = future.pop(); } },
};
}
const h = createHistory(1);
h.set(2); h.set(3); h.undo();
console.log(h.get()); // 2
Practice: Undoable User Table
284. Build a dropdown menu or emoji picker.
A button toggles the menu (aria-expanded, aria-haspopup), arrow keys move through items, Enter selects, Escape closes and returns focus to the button, and clicking outside closes it. Position it so it flips when there’s no room below. For a picker with search, filter the list as the user types and keep the active item in view.
Practice: Emoji Selector. Deep dive: Design an action menu
285. Build a digital or analog clock.
Update once per second, aligned to the start of the next second so it doesn’t drift visibly, and clear the timer on unmount. For an analog clock, rotate hands with transform: rotate(): the hour hand moves 30 degrees per hour plus 0.5 per minute. Format digital time with Intl.DateTimeFormat to respect the user’s locale.
Practice: Wall Clock and Seven Segment Clock
Senior Frontend Interview Questions: System Design and Behavioral

Find in-depth explanations and practice here: Frontend system design questions ->
Senior frontend interview questions shift from “do you know this” to “how do you decide”. System design and behavioral rounds often carry the most weight in the leveling decision, so prepare for them as seriously as for coding.
286. What is a frontend system design interview?
A 45 to 60 minute discussion where you design the client side of a product, such as a news feed, a chat app, or an autocomplete. You’re judged on requirements gathering, component architecture, state and data modeling, API design, and performance, accessibility, and offline trade-offs. There’s no code to run; the conversation is the output.
Deep dive: Frontend system design interview guide
287. What framework should you use to structure a system design answer?
- Requirements: functional (what it does) and non-functional (performance, devices, offline, accessibility, scale).
- Architecture: the main components and how they talk to each other.
- Data model: client-side entities and state, and where each piece lives.
- API: endpoints or real-time channels, pagination, and payload shapes.
- Optimizations: performance, accessibility, security, and internationalization deep dives.
Deep dive: Frontend system design interview framework
288. Design a news feed.
Key points: cursor-based pagination (offsets break when new posts arrive), infinite scroll with virtualization, a normalized cache so a liked post updates everywhere, optimistic updates for likes and comments, a “new posts” pill instead of jumping content, and lazy-loaded media with reserved dimensions to avoid layout shift.
Deep dive: Design a news feed
289. Design a chat application.
Key points: WebSockets for real-time messages with reconnection and backoff, client-generated message IDs so retries don’t duplicate, optimistic sending with “sending”, “sent”, and “failed” states, message ordering by server timestamp or sequence number, virtualized message history loaded upward, and an offline queue in IndexedDB.
Deep dive: Design a chat app
290. Design an autocomplete component for a large product.
Key points: debounced requests with cancellation, a client-side cache of recent queries (LRU), showing cached results instantly while fetching fresh ones, keyboard and screen reader support (combobox pattern), handling slow and failed responses, and making it configurable (data source, result rendering) because many teams will reuse it.
Deep dive: Design an autocomplete
291. How do you design client-side state for a complex app?
Separate server state (cached API data, normalized by ID) from client state (UI state, drafts). Keep state close to where it’s used, put shareable state in the URL, and derive everything else. Normalizing entities avoids the bug where the same item shows different data in two places.
Deep dive: Data model and Normalization
292. How do you structure a large frontend codebase?
By feature, with clear layers inside each feature (UI, state and view logic, data access) and dependencies pointing one way. Shared UI lives in a design system package, and features expose a small public API. Lint rules enforce boundaries so the structure survives team growth.
Deep dive: Design a scalable frontend architecture and Layered frontend architecture
293. What are micro frontends, and when are they worth it?
Splitting a frontend into independently built and deployed pieces owned by different teams, composed at build time, on the server, or in the browser (Module Federation). They help when many teams block each other on one release. The costs are duplicated dependencies, inconsistent UX, and complex shared state, so a well-structured monorepo is usually the better first step.
294. How do you design a component library or design system?
Start from design tokens (colors, spacing, typography as variables), build accessible primitives first (button, input, dialog, menu), use composition over configuration (slots and children instead of dozens of props), document every component with examples, and version it with clear deprecation paths. Measure adoption and collect feedback from product teams.
295. How do you make a frontend work offline?
Cache the app shell with a service worker, store data in IndexedDB, queue writes while offline and sync when back online, and show clear offline and syncing states. The hard part is conflict resolution when the same data changed on the server: last write wins, merge rules, or asking the user.
296. How do you handle internationalization at scale?
Externalize strings with an ICU message format for plurals and variables, format dates, numbers, and currencies with Intl, support right-to-left with logical CSS properties, design for text expansion, and load locale bundles lazily. Never concatenate translated fragments; word order differs across languages.
297. How do you monitor a frontend in production?
Error tracking with source maps and release tags, real-user monitoring of Core Web Vitals by route and device, logging of failed API calls, and alerts on error-rate and performance regressions after deploys. Feature flags let you turn off a broken feature without a redeploy.
Practice: Build a Feature Flag. Deep dive: Design a feature flag SDK
298. How do you decide between building and buying (or using a library)?
Use a library when the problem is hard and not your product’s differentiator: date handling, rich text editing, accessible comboboxes. Build when the library would cost more than it saves (bundle size, customization fights, abandoned maintenance) or when the feature is core to your product. Check maintenance, size, accessibility, and license before adopting.
299. How do you lead a large frontend migration?
Make the case with measurable goals, migrate incrementally (strangler pattern: new code in the new stack, old code moved route by route), run both side by side behind flags, automate the repetitive parts with codemods, and track progress publicly. Big-bang rewrites stall and rarely finish.
300. How do you prepare for the behavioral round?
Prepare 6 to 8 stories from real work that cover a conflict, a failure, a hard technical decision, leading without authority, a tight deadline, and helping others grow. Tell each with the STAR method (situation, task, action, result), focus on your own actions, and end with a measurable result and what you learned.
Deep dive: STAR method and Behavioral interview for frontend engineers
301. How do you answer “Tell me about a time you disagreed with a teammate”?
Pick a real technical disagreement, explain both positions fairly, show how you resolved it with data or a small experiment rather than authority, and describe the outcome and the relationship afterward. Interviewers are checking for maturity, not for who was right.
Deep dive: Dispute with a colleague
302. How do you answer “Tell me about a project you’re proud of”?
Choose one with real scope and your clear ownership. Cover the problem and why it mattered, the hardest technical decision and the alternatives you rejected, how you worked with others, and the impact with numbers. Expect follow-up questions, so pick something you can go deep on.
Deep dive: Challenge in a project
303. How do you answer “Why do you want to work here?”
Connect something specific about the company (its product, its engineering challenges, its users) with what you want to do next and what you bring. Generic praise sounds rehearsed; a specific detail shows you did your research.
Deep dive: Why work here?
304. What questions should you ask your interviewers?
Ask about how the team works and what success looks like: “What would make someone successful in this role in the first six months?”, “How are frontend architecture decisions made?”, “What’s the biggest technical challenge the team faces this year?” Good questions show judgment and help you decide whether you want the job.
305. How do frontend interviews differ by company?
Formats vary: some companies focus on JavaScript and UI coding rounds, some lean on algorithms, and senior loops almost always add frontend system design and behavioral rounds. Ask your recruiter for the format of each round, then weight your preparation to match.
Deep dive: Frontend interview question types by company and The frontend interview process
How to Use This List
You don’t need all 305 questions before your next interview. Front end interview questions don’t change much from year to year, but the emphasis shifts with the level of the role. Pick the path that matches yours:
| Level | Study first | Then |
|---|---|---|
| Junior or new grad | HTML, CSS, layout, and JavaScript essentials (Q1-125) | The first 10 UI coding questions |
| Mid-level | The browser, frameworks, performance, and accessibility (Q126-230), plus all UI coding questions | Security and testing |
| Senior | Performance, security, and the senior frontend interview questions (Q186-245, Q286-305) | Two or three full system design problems, out loud, on a timer |
Reading answers isn’t the same as producing them under pressure. For each section, close the page and explain three questions out loud. Then build the linked components in the editor, where tests tell you whether your solution actually works.
More ways to prepare on FrontendLead:
- 300+ JavaScript interview questions and answers and 300+ React interview questions and answers for deeper coverage.
- A 4-week frontend interview study plan and the study plans if you want a schedule.
- Trivia questions and Quiz Yourself for quick concept review.
- Frontend system design questions and behavioral questions for senior loops.
- The frontend interview handbook for the whole process, from resume to offer negotiation.
Related reading: How to become a frontend developer: a step-by-step roadmap · Frontend frameworks compared: React vs Vue vs Angular vs Svelte · Frontend vs backend: differences, skills, and pay · Micro frontends and the backend for frontend pattern
