Developer Workflow for Debugging UI Bugs

· 9 min read · Workflow

Systematic workflow for debugging UI bugs including isolation techniques, DevTools usage, and hypothesis-driven debugging.

Developer Workflow for Debugging UI Bugs

UI bugs are frustrating because they often involve multiple systems: CSS layout, JavaScript logic, framework state, and browser rendering. A systematic workflow helps you diagnose issues faster and build mental models that prevent similar bugs in the future.

Problem

Developers often approach UI bugs randomly:

  1. Change something
  2. Refresh
  3. It did not work
  4. Change something else
  5. Repeat

This trial-and-error approach is slow and does not build understanding. Even when it works, you may not know why it worked.

Why It Happens

UI bugs have many potential causes:

  • CSS specificity or cascade issues
  • Layout algorithm misunderstandings
  • JavaScript timing or state problems
  • Browser inconsistencies
  • Framework rendering quirks

Without a systematic approach, you are essentially guessing which category the bug falls into.

Solution

Follow a structured debugging workflow that narrows down the problem space efficiently.

Implementation

Step 1: Reproduce Reliably

Before debugging, ensure you can reproduce the bug consistently:

Reproduction steps:
1. Navigate to /blog
2. Click first article
3. Scroll to "Implementation" section
4. TOC should highlight "Implementation"
5. BUG: TOC highlights "Problem" instead

If the bug is intermittent, find the conditions that trigger it.

Step 2: Isolate the Component

Render the component in isolation to determine if the bug is in the component or its context:

// pages/debug.tsx
import { TOC } from '../components/TOC';

const testContent = `
## Problem
First section.

## Implementation
Second section.
`;

export default function Debug() {
  return (
    <div style={{ padding: 100 }}>
      <TOC content={testContent} />
    </div>
  );
}

If the bug disappears, the issue is in how the component is used, not the component itself.

Step 3: Check DevTools

Open DevTools and examine:

  • Elements panel: Check computed styles, box model, applied rules
  • Console: Look for errors or warnings
  • Network: Verify resources loaded correctly
  • Performance: Check for layout thrashing or long tasks

For CSS issues, right-click the element and select "Inspect" to see exactly which rules apply.

Step 4: Add Debug Logging

Add temporary logging to understand runtime behavior:

useEffect(() => {
  console.log('Headings:', headings);
  console.log('Active ID:', activeId);
  
  const observer = new IntersectionObserver((entries) => {
    console.log('Intersection entries:', entries.map(e => ({
      id: e.target.id,
      isIntersecting: e.isIntersecting,
      ratio: e.intersectionRatio
    })));
    // ...
  });
}, [headings]);

TIP: Use console.table() for array data and console.dir() for DOM elements to see their properties clearly.

Step 5: Form a Hypothesis

Based on your observations, form a specific hypothesis:

"The IntersectionObserver rootMargin is configured for the wrong viewport height, causing headings to register as visible too early."

Step 6: Test the Hypothesis

Make a targeted change to test your hypothesis:

// Change rootMargin to test hypothesis
const observer = new IntersectionObserver(
  callback,
  { 
    rootMargin: '-120px 0px -60% 0px' // Adjusted for fixed header
  }
);

If this fixes the bug, your hypothesis was correct. If not, return to Step 4 with new logging.

Example

Debugging a sidebar that overlaps content on mobile:

Step 1: Reproduce

  • Viewport width: 768px
  • Sidebar visually overlaps article content

Step 2: Isolate

  • Rendered sidebar alone: displays correctly
  • Issue is layout interaction

Step 3: DevTools

  • Sidebar has position: fixed but no width constraint
  • On mobile, it takes width: 280px which extends beyond viewport

Step 4: Log

console.log('Viewport:', window.innerWidth);
console.log('Sidebar rect:', sidebarRef.current?.getBoundingClientRect());

Output: Sidebar extends 280px from left, viewport is 768px, but left padding pushes content under sidebar.

Step 5: Hypothesis "Sidebar should be hidden on viewports under 1024px."

Step 6: Test

@media (max-width: 1023px) {
  .sidebar {
    display: none;
  }
}

Bug fixed.

Common Mistakes

Changing multiple things at once

/* Do NOT do this */
.element {
  position: relative; /* Changed */
  z-index: 10; /* Changed */
  overflow: visible; /* Changed */
}

Change one property, test, then change the next if needed.

Not checking error console

Many CSS issues trigger console warnings:

DevTools: "position: sticky" has no effect because the parent element has "overflow: hidden"

Browser warnings often point directly to the cause.

Assuming the bug is where it appears

The visual symptom and root cause are often in different components:

Symptom: Button appears behind modal
Cause: Ancestor three levels up creates stacking context

WARNING: The element with the visual bug is not necessarily the element you need to fix. Trace up the ancestor chain.

Not testing on actual devices

Some bugs only appear on real mobile devices due to:

  • Touch interactions
  • Viewport units
  • Safe area insets
  • Browser rendering differences

Conclusion

Debug UI bugs systematically: reproduce, isolate, inspect, hypothesize, test. Make one change at a time and verify each step. Use browser DevTools extensively—the Elements panel and Console contain most of the information you need. Build mental models of CSS and JavaScript behavior so you can form hypotheses faster over time.