Skip to content
Frontend Interview Guide: HTML, CSS, JavaScript, React, and System Design

Frontend Interview Guide: HTML, CSS, JavaScript, React, and System Design

DodaTech Updated Jun 20, 2026 6 min read

Frontend engineering interviews assess your understanding of browser technologies, framework internals, performance optimization, accessibility, and your ability to design and build user interfaces that are fast, accessible, and maintainable.

What You’ll Learn

  • Common HTML, CSS, and JavaScript interview questions and answers
  • React and Angular framework internals and best practices
  • Frontend system design: component architecture, state management, and routing
  • Performance optimization: Core Web Vitals, lazy loading, and bundle optimization
  • Accessibility (a11y) and internationalization (i18n) patterns

Why Frontend Interview Prep Matters

Frontend interviews differ from general software engineering interviews. They test browser APIs, CSS layout, framework internals, and performance optimization — topics that generic coding practice doesn’t cover. Companies like Google, Meta, and Stripe have dedicated frontend interview tracks that focus on these skills.

Doda Browser looks for frontend engineers who understand browser rendering, accessibility, and performance — building a browser requires deep knowledge of how web technologies work at every level.

Learning Path

    flowchart LR
  A[Coding Interview Prep] --> B[Frontend Interview Guide<br/>You are here]
  B --> C[Backend Interview Guide]
  C --> D[System Design]
  D --> E[Behavioral Prep]
  style B fill:#f90,color:#fff
  

HTML and CSS

Semantic HTML

<!-- BAD: Div soup -->
<div class="header">
  <div class="nav">
    <div class="nav-item">Home</div>
  </div>
</div>

<!-- GOOD: Semantic elements -->
<header>
  <nav>
    <ul>
      <li><a href="/">Home</a></li>
    </ul>
  </nav>
</header>

CSS Layout

/* Flexbox — one-dimensional layout */
.container {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

/* CSS Grid — two-dimensional layout */
.grid-container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 2rem;
}

Specificity and Cascading

/* Specificity hierarchy:
   inline > ID > class/attribute/pseudo-class > element/pseudo-element */

#header { color: red; }         /* 0-1-0 */
.header { color: blue; }        /* 0-0-1 */
div { color: green; }           /* 0-0-0 */

/* !important overrides all — avoid it */
.special { color: purple !important; }

JavaScript Fundamentals

Closures

function createCounter() {
  let count = 0;
  return {
    increment: () => ++count,
    decrement: () => --count,
    getCount: () => count,
  };
}

const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.decrement(); // 1
console.log(counter.getCount()); // 1

Event Loop and Async

console.log('1: Sync');

setTimeout(() => console.log('2: setTimeout'), 0);

Promise.resolve().then(() => console.log('3: Microtask'));

console.log('4: Sync');

// Output: 1, 4, 3, 2
// Microtasks (Promise) run before macrotasks (setTimeout)

Debouncing and Throttling

// Debounce — wait for pause before executing
function debounce(fn, delay) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

// Throttle — execute at most once per interval
function throttle(fn, interval) {
  let lastCall = 0;
  return (...args) => {
    const now = Date.now();
    if (now - lastCall >= interval) {
      lastCall = now;
      fn(...args);
    }
  };
}

React

Component Lifecycle and Hooks

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let cancelled = false;

    async function fetchUser() {
      setLoading(true);
      const data = await api.getUser(userId);
      if (!cancelled) {
        setUser(data);
        setLoading(false);
      }
    }

    fetchUser();
    return () => { cancelled = true; };
  }, [userId]);

  if (loading) return <Spinner />;
  return <div>{user.name}</div>;
}

Performance Optimization

// React.memo — prevent unnecessary re-renders
const ExpensiveList = React.memo(({ items }) => {
  return items.map(item => <ListItem key={item.id} item={item} />);
});

// useMemo — memoize computed values
function Dashboard({ transactions }) {
  const totals = useMemo(() => {
    return transactions.reduce((acc, t) => acc + t.amount, 0);
  }, [transactions]);
}

// useCallback — memoize callbacks
function Parent() {
  const handleClick = useCallback((id) => {
    console.log('Clicked:', id);
  }, []);
}

Accessibility (a11y)

<!-- Accessible button -->
<button aria-label="Close dialog" onclick="close()">
  <span aria-hidden="true">×</span>
</button>

<!-- Accessible form -->
<label for="email">Email address</label>
<input
  id="email"
  type="email"
  aria-describedby="email-hint"
  required
/>
<span id="email-hint">We'll never share your email.</span>

<!-- Skip navigation link -->
<a href="#main-content" class="skip-link">Skip to content</a>

Frontend System Design

Design a Search Bar Component

Requirements:
- Real-time search suggestions
- Debounced API calls
- Loading and error states
- Keyboard navigation (arrow keys)
- Accessible (ARIA combobox pattern)

State:
- query: string
- suggestions: Suggestion[]
- isLoading: boolean
- error: string | null
- selectedIndex: number
- isOpen: boolean

Architecture:
SearchBar
├── Input (controlled)
├── SuggestionsList
│   └── SuggestionItem (highlighted, with keyboard nav)
└── useSearch (custom hook: debounce, fetch, cache)
function useSearch(query) {
  const [results, setResults] = useState([]);
  const [loading, setLoading] = useState(false);
  const debouncedQuery = useDebounce(query, 300);

  useEffect(() => {
    if (!debouncedQuery) {
      setResults([]);
      return;
    }
    setLoading(true);
    fetch(`/api/search?q=${debouncedQuery}`)
      .then(r => r.json())
      .then(data => {
        setResults(data);
        setLoading(false);
      });
  }, [debouncedQuery]);

  return { results, loading };
}

Common Frontend Interview Mistakes

1. Not Knowing the Browser Rendering Pipeline

Not understanding Critical Rendering Path, reflow vs repaint, and layout thrashing.

Fix: Learn: DOM → CSSOM → Render Tree → Layout → Paint → Composite.

2. Focusing Only on Framework APIs

Knowing React hooks syntax but not understanding when re-renders happen or why.

Fix: Understand the underlying concepts: virtual DOM, reconciliation, fiber architecture.

3. Ignoring Accessibility

Saying “we’ll add accessibility later” is a red flag at most companies.

Fix: Learn ARIA roles, semantic HTML, keyboard navigation, and screen reader behavior.

4. No Performance Awareness

Writing components that cause excessive re-renders, large bundles, or blocking network requests.

Fix: Know Core Web Vitals, bundle analysis, code splitting, and lazy loading.

5. Weak CSS Skills

Knowing Flexbox but not Grid, or not understanding stacking contexts.

Fix: Practice complex layouts — responsive grids, sticky footers, overlapping elements.

6. Not Testing Frontend Code

Frontend code is notoriously hard to test, but not testing at all is unacceptable.

Fix: Know Testing Library, component tests, integration tests, and E2E testing.

7. Over-Engineering Solutions

Adding Redux for a 3-component app or reaching for micro-frontends unnecessarily.

Fix: Start simple. Introduce complexity only when needed.

Practice Questions

1. What is the difference between debouncing and throttling?

Debouncing waits for a pause in calls before executing. Throttling executes at most once per interval, regardless of call frequency.

2. How does React determine when to re-render a component?

When state changes (useState), when props change, or when a parent re-renders. React.memo and useMemo can prevent unnecessary re-renders.

3. What are Core Web Vitals?

LCP (Largest Contentful Paint — loading), INP (Interaction to Next Paint — interactivity), CLS (Cumulative Layout Shift — visual stability).

4. What is the difference between reflow and repaint?

Reflow recalculates element positions and sizes (expensive). Repaint redraws pixels without layout changes (cheaper).

5. How do you make a web application accessible?

Use semantic HTML, proper ARIA attributes, keyboard navigation, sufficient color contrast, screen reader announcements, and focus management.

Challenge: Design and implement an autocomplete/search component with debounced API calls, keyboard navigation, loading states, and full accessibility support. Write tests for each interaction.

FAQ

Should I learn React or Angular for interviews?
React is more commonly asked in general frontend interviews. If you’re targeting Angular shops specifically, learn Angular — but React knowledge is more portable.
Do I need to know TypeScript for frontend interviews?
Yes — TypeScript is the standard for modern frontend development. Know interfaces, types, generics, and utility types.
What are the most common frontend interview questions?
Event loop, closures, this binding, CSS specificity, React hooks, state management, performance optimization, and accessibility.
How do I prepare for frontend system design?
Practice designing common components (search, infinite scroll, form builder, data table) and full-page layouts (dashboard, e-commerce product page).
Do I need to understand build tools?
Know webpack, Vite, and basic configuration. Understand tree-shaking, code splitting, and bundle analysis.

What’s Next

TutorialWhat You’ll Learn
Backend Interview GuideAPI design, databases, scalability
System Design InterviewDesigning large-scale web applications
Behavioral Interview PrepBehavioral questions and storytelling

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-20.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro