Beyond the Tutorials: What Frontend Interviews Really Test and Why It Matters


You’ve got the basics down — React, HTML/CSS, a couple of CRUD apps. Maybe even a few projects on your GitHub that you're proud of. You’re officially not in tutorial hell anymore. Hurray!
But when you sit across from an interviewer and they ask:
“Can you talk about performance optimization in your projects?”
or
“What’s the hardest bug you’ve ever solved?”
That’s when things get real.
This isn’t about white-boarding algorithms. It’s about showing that you understand how to build for the real world — where page load times matter, bundles grow without warning, and features need to work on a 4G phone in a rural town, not just your MacBook Pro.
This article is for frontend devs who want to move beyond tutorials and prepare for interviews that test how you think, how you debug, and how you solve problems.
The Bug That Made Me a Better Developer
Let’s start with the classic interview question:
"What’s the most difficult bug you’ve dealt with?"
This question is really an opportunity to show off — just a little — that you know your way around modern web development. But how do you make sure you’re telling a story that’s compelling, technically solid, and gives the interviewer insight into how you think?
Here’s an example of how I’d go about it:
In one of my earlier projects, I had built a dashboard that worked beautifully on desktop. But users on mobile were complaining that it was sluggish and sometimes didn’t respond at all.
I ran Lighthouse audits and noticed long scripting times. Turned out, I had rendered an entire table of thousands of rows—even when most weren’t visible.
That moment introduced me to:
Lazy Loading
Example:
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
);
}
Virtualization
Example:
import { FixedSizeList as List } from 'react-window';
const MyList = ({ items }) => (
<List height={400} itemCount={items.length} itemSize={35} width={300}>
{({ index, style }) => <div style={style}>{items[index]}</div>}
</List>
);
The results? Page load dropped from 8 seconds to under 2 seconds, and time-to-interactive was cut in half.
Optimization Isn’t a Buzzword, It’s a Habit
The word “optimization” gets thrown around a lot in interviews, but what does it actually mean in a frontend context?
Real-World Examples
Concept | Where I Applied It |
Code Splitting | Broke up monolithic bundle into dynamic imports |
Tree Shaking | Switched from lodash to lodash-es |
Memoization | Used useMemo() & useCallback() around complex renders |
Image Optimization | Used srcSet & compressed WebP images |
useEffect Hygiene | Cleaned up subscriptions & timers |
When you talk about these things in interviews, don’t just drop the term—tell the story of when you used it, and how it made something faster, smoother, or more reliable.
From Component Hell to Clean Architecture
How do you structure your React projects?
In a recent team project, we had components bloated with logic, props drilling all the way down, and repeated logic across screens. It wasn’t scalable.
So I proposed and led a refactor into:
Feature-based folders (e.g.,
/auth
,/dashboard
)Hooks for business logic, shared across screens
Context API to lift state where needed
Error boundaries and
Suspense
for resilience
This made onboarding faster, reduced bugs, and made features more isolated for testing.
"Explain Virtual DOM" — But Show You Actually Get It
Now, when asked what the Virtual DOM is, I keep it simple:
“It’s React’s lightweight representation of the actual DOM. When state changes, React compares the new Virtual DOM with the previous one, and updates only what’s changed in the real DOM—this is what makes React fast.”
But then I go further:
const MemoizedList = React.memo(({ items }) => {
return (
<ul>
{items.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
);
});
That’s how you go from buzzword to proof.
Bundles, Build Tools & The Day I Discovered Source Maps
Debugging a production bug in a minified JS file taught me the power of source maps and bundle analyzers.
// Analyze your build size
pnpm add -D webpack-bundle-analyzer
With it, I learned:
One tiny package was pulling in half a megabyte of unused code
I could replace
moment.js
with native Intl.DateTimeFormatI could switch to PNPM for faster, leaner installs
Testing Like a Dev Who Cares
When asked, “Do you write tests?”—your answer should never be a plain “Yes.”
Instead, talk about:
Testing stateful logic in custom hooks
Writing E2E tests with Cypress, or Playwright
Catching regressions before they ship
// React Testing Library
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import LoginForm from './LoginForm';
it('displays error on empty submit', () => {
render(<LoginForm />);
userEvent.click(screen.getByText(/Submit/i));
expect(screen.getByText(/required/i)).toBeInTheDocument();
});
From Buzzwords to Real Impact
Here’s the real lesson:
Most interviewers don’t care if you memorize every hook or know the React docs by heart.
They care if you know how to solve problems. They care if you've been in the trenches — debugging layout issues at midnight, optimizing bundles for low-end devices, fixing bugs you can’t reproduce easily.
So here’s what I leave you with:
Build projects that simulate the real world (think dashboards, marketplaces, admin panels)
Optimize not just for performance, but for clarity and scalability
Don’t just say “I used lazy loading.” Tell them why, when, and what changed
Because interviews aren’t exams.
They’re conversations about what kind of developer you are — and how you think.
Common Buzzwords — That Are Really Engineering Wisdom
Here are some of the frontend buzzwords you’ll hear in interviews — and more importantly, what they really mean in practice.
10 Concepts to Know, Live, and Breathe
1. Lazy load images & components
Definition:
Lazy loading is a design pattern that delays the loading of non-critical resources until they’re needed, improving initial load time and performance.
Why It Matters:
Why load everything at once if the user may never scroll to it? By splitting your code and images, you can serve a faster, more responsive experience.
React Example – Components:
import React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
For images:
<img src="image.jpg" loading="lazy" alt="..." />
Or using IntersectionObserver
:
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.src = entry.target.dataset.src;
observer.unobserve(entry.target);
}
});
});
2. Make YOUR UI Accessible (WCAG)
Definition:
Accessibility (a11y) ensures your app can be used by people with disabilities — from keyboard users to screen readers.
Why It Matters:
It’s not just about compliance — it’s about empathy. Plus, it's required by law in many countries.
Best Practices:
Use semantic HTML (
<button>
,<nav>
,<header>
)Use ARIA attributes when necessary
Ensure focus is visible and manageable
Always test with keyboard navigation
Code Tip:
<button aria-label="Close" onClick={closeModal}>
<span aria-hidden="true">×</span>
</button>
3. Infinite Scrolling / Pagination
Definition:
Load more data as the user scrolls or paginates through content — improving performance and UX by not loading everything upfront.
When to Use What:
Infinite scroll for feeds (e.g., Twitter)
Pagination for search (e.g., Google)
With react-window (virtualization):
import { FixedSizeList as List } from 'react-window';
<List
height={400}
itemCount={items.length}
itemSize={35}
width="100%"
>
{({ index, style }) => (
<div style={style}>{items[index]}</div>
)}
</List>
4. Design for Mobile
Definition:
Responsive design ensures your UI works across different screen sizes, from mobile to desktop.
Why It Matters:
Over 50% of users browse on mobile. If your app breaks on phones, you’ve already lost.
Code Tip:
.container {
display: grid;
grid-template-columns: 1fr;
}
@media(min-width: 768px) {
.container {
grid-template-columns: 1fr 1fr;
}
}
5. Handle Browser Compatibility
Definition:
Ensure your site works consistently across all major browsers.
Why It Matters:
Different browsers interpret code slightly differently. Testing ensures a consistent user experience.
How to Do It:
Test with BrowserStack or in-browser dev tools
Avoid non-standard APIs
Tools: BrowserStack, Sauce Labs, or real devices.
6. Optimize Bundle Size
Definition:
Bundle size refers to the amount of JavaScript and assets downloaded when your app loads.
Smaller bundles = faster apps.
Why It Matters:
Large bundles slow down page load and can frustrate users, especially on mobile networks.
Strategies:
Code splitting (React.lazy + Suspense)
Tree shaking (remove unused exports via modern bundlers like Vite or Webpack)
Dynamic imports
Code Tip:
const Modal = React.lazy(() => import('./Modal'));
7. Handle Forms Effectively
Definition:
Forms are central to most apps — they need to be intuitive, validated, and performant.
Why It Matters:
Bad form UX = rage quits.
Good form UX = conversions.
React Hook Form:
import { useForm } from 'react-hook-form';
function MyForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<input {...register('email', { required: true })} />
{errors.email && <p>Email is required</p>}
</form>
);
}
8. Build Responsive Navigation
Definition:
Design menus and navigation that work across devices — touch, keyboard, and screen reader.
Why It Matters:
Navigation is your app’s map. If it’s confusing or inaccessible, users will leave.
Code Tip – Hamburger Menu:
import { useState } from 'react';
function MobileNav() {
const [isOpen, setIsOpen] = useState(false);
const toggleMenu = () => setIsOpen(prev => !prev);
return (
<div>
<button
onClick={toggleMenu}
aria-label="Toggle menu"
aria-expanded={isOpen}
aria-controls="mobile-menu"
className="text-2xl"
>
☰
</button>
<nav
id="mobile-menu"
className={`${isOpen ? 'block' : 'hidden'} mt-2`}
>
<ul className="space-y-2">
<li>
<a href="/home" className="block text-blue-600 hover:underline">
Home
</a>
</li>
{/* Add more links here */}
</ul>
</nav>
</div>
);
}
9. Add Smooth Animations
Definition:
Animations bring your UI to life — transitions, hover effects, modals, etc.
Why It Matters:
They guide users, create delight, and improve usability — if done subtly.
With Framer Motion:
import { motion } from 'framer-motion';
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
Hello World!
</motion.div>
10. Set Up State Management
Definition:
State management is how you handle and share dynamic data (like user info or form inputs) across your app.
When to Use What:
useState/useReducer
→ local component logicContext
→ light global state (e.g. theme, auth)Redux/Zustand/Recoil
→ complex apps with lots of shared logic
Code Tip – Zustand:
import { create } from 'zustand';
const useStore = create(set => ({
count: 0,
increment: () => set(state => ({ count: state.count + 1 }))
}));
function Counter() {
const { count, increment } = useStore();
return <button onClick={increment}>{count}</button>;
}
9 Interview Questions That Are Really Just Good Engineering Prompts
Don’t get psyched out by “tricky” questions. Most interviewers just want to know how you think about tradeoffs, architecture, and user experience.
1. How do you design a scalable, reusable component library for a large web app?
→ Talk about atomic design, design systems, and using Storybook for isolated component testing.
2. How do you ensure responsiveness in your application across different devices?
→ Mention Flexbox, Grid, media queries, and maybe even CSS-in-JS libraries like Emotion or Styled Components.
3. How do you implement and optimize a UI component like a modal or a dropdown?
→ Explain useRef
, useEffect
, event delegation, closing on outside click/ESC, and accessibility.
4. How do you approach managing state in complex React apps?
→ Context for global light data, Redux for large apps, Zustand or Recoil for leaner needs, useReducer
for local logic-heavy state.
5. What’s your approach to error boundaries and handling unexpected errors in React?
→ Mention ErrorBoundary
components, logging tools like Sentry, and user-friendly error states.
6. How do you handle routing in single-page applications?
→ React Router, dynamic routing, nested routes, and lazy-loaded route components.
7. How do you ensure accessibility in your web applications?
→ Semantic HTML, ARIA attributes, keyboard navigation, and screen reader support.
8. How do you handle form validation in a React app?
→ Client-side validation with Yup + React Hook Form, plus server-side error messaging for edge cases.
9. How do you optimize an application for high interactivity (e.g., complex forms or real-time updates)?
→ Throttling, debouncing, useMemo
, useCallback
, and WebSockets if needed.
Final Thoughts: Build, Break, Brag (a Little)
The best way to prepare for these interviews? Build something ambitious, break it, fix it, and write about it. The more you internalize these patterns, the more natural your answers will feel.
And if all else fails, don’t be afraid to say,
“I don’t know offhand, but here’s how I’d figure it out…”
That’s also a flex.
Action step:
Pick one concept from this article—lazy loading, bundle analysis, testing—and revisit one of your old projects. Can you improve it using what you’ve just read?
Let your projects be your prep.
Let your bugs be your brag.
Subscribe to my newsletter
Read articles from Bridgit Kanini directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
