The Debugger Panel

🐛 Lesson 5 — The Debugger Panel

The Debugger lets you pause JavaScript at any line, step through code one statement at a time, and read the exact value of every variable — replacing guesswork with certainty. Press Ctrl + Shift + Z to open it directly, or click the Debugger tab after pressing F12.

🗺️ The Debugger Interface

{ } ⏸ Paused on breakpoint Ctrl+P — search files
▾ src/
▾ components/
auth.js ●
dashboard.js
▸ utils/
app.js
vendor.min.js
38
// validate and return user object
39
async function getUserName(userId) {
40
const user = await fetchUser(userId);
41
if (!user) throw new Error('User not found');
42
return user.profile.name;
43
}
44
45
async function initDashboard() {
46
const name = await getUserName(currentUser.id);
Call Stack
getUserName
auth.js:41
initDashboard
app.js:46
DOMContentLoaded
app.js:3
Scopes
Local
userId 42
user undefined
Closure
authToken "eyJ…"

The mockup shows execution paused on line 41 — the conditional breakpoint (orange dot). The Call Stack tells us getUserName was called by initDashboard. The Scopes panel reveals that user is undefined — which is exactly why the next line would throw.

🔴 Breakpoint Types

Line Breakpoint
Pauses every time execution reaches that line — unconditionally. The most common type.
Click the line number in the gutter. Blue dot appears. Click again to remove.
Conditional Breakpoint
Pauses only when a JavaScript expression is true. Essential when a bug only occurs for specific data values.
Right-click line number → Add Conditional Breakpoint → type expression. Orange dot appears.
Logpoint
Logs a value to the Console without pausing. Ideal for loops or high-frequency events where a pause every iteration would be unbearable.
Right-click line number → Add Log → type expression. Purple dot appears.
Exception Breakpoint
Pauses the moment any exception is thrown — before it propagates, before any catch runs. The fastest way to find the origin of an error.
Click the ⬡ hexagon icon in the toolbar. Choose caught, uncaught, or both.

Conditional Breakpoint Examples

// Only pause when the user id is 42 user.id === 42 // Only pause when the array is unexpectedly empty items.length === 0 // Only pause on a specific iteration i === 99 // Only pause when a fetch returns an error status response.status >= 400

⏯️ Stepping Controls

Once paused, these controls move execution forward at your own pace:

Resume
F8
Continue running until the next breakpoint (or end of script).
Step Over
F10
Run the current line and move to the next. Function calls run in full without entering them.
Step Into
F11
If the current line calls a function, move the cursor inside that function's body.
Step Out
Shift + F11
Run to the end of the current function and pause in the calling function.
SituationUse
Moving forward through your own codeStep Over (F10) — the default
Want to see what a function you wrote doesStep Into (F11)
Accidentally stepped into library/framework codeStep Out (Shift+F11) immediately
Seen what you need, ready for the next breakpointResume (F8)

📚 The Call Stack

The Call Stack shows the chain of function calls that led to the current execution point. The most recent call is at the top; the entry point is at the bottom. Click any frame to jump to that point in the source and see that frame's variables in the Scopes panel.

Call Stack — paused at auth.js:41
0
getUserName
auth.js:41
paused here
1
initDashboard
app.js:46
2
DOMContentLoaded handler
app.js:3
3
(event dispatch — browser)
💡 Click a Frame to Travel Back in Time Clicking frame 1 (initDashboard / app.js:46) jumps the editor to that line and updates the Scopes panel to show the variables that existed when initDashboard called getUserName. You can inspect the full context of every caller without restarting.

🔎 Scopes and Watch Expressions

Scopes
Local (getUserName, auth.js:41)
userId42
userundefined
Closure
authToken"eyJhbGci…"
baseUrl"https://api.example.com"
Global
currentUserObject { id: 42, role: "admin" }

The user variable is undefined — the fetch returned nothing for userId 42. This instantly explains the error on the next line. Double-click any value in the Scopes panel to edit it and continue execution with the modified value — a fast way to test a fix without reloading.

ℹ️ Watch Expressions The Watch panel (below Scopes) lets you type arbitrary JavaScript expressions that re-evaluate every time you step. Type things like user?.profile?.email or items.filter(i => !i.active).length to track derived values that aren't directly available as variables.

🚫 Blackboxing (Ignore List)

When stepping through code you'll often accidentally enter library or framework internals (React, jQuery, bundler boilerplate) that you didn't write. Blackboxing tells the Debugger to skip those files entirely.

💡 How to Blackbox a File Right-click any file in the file tree → Ignore Source. The file turns grey. The Debugger will never pause inside it — even if a breakpoint is set there, execution flows straight through. You can also right-click any frame in the Call Stack → Ignore Source to blackbox that file while already paused.
⚠ Don't blackbox your own files — only library and vendor files. Blackboxed files are skipped completely; if you blackbox app.js by mistake, your breakpoints there will stop working. Firefox Settings → Ignore List lets you review and remove blackboxed files.

🗺️ Source Maps

Modern apps bundle and minify JavaScript before shipping. Source maps are companion .js.map files that tell the Debugger how the minified output maps back to the original source — so you debug against the code you wrote, not the code the browser runs.

SituationWhat you see in the DebuggerWhat to do
Source maps available Original file tree — individual components, TypeScript files, proper variable names Debug normally. Set breakpoints in the original source.
No source maps One long line of mangled code — var a=function(b,c){…} Click { } (Pretty Print) at the bottom of the editor to reformat. You can still set breakpoints, but variable names are cryptic.
Source maps loaded but paths wrong File tree shows original files but clicking them shows 404 Check the sourceRoot field in the .js.map file — the path prefix may be wrong for your local setup.

🔧 Practical Debugging Workflow

📋 Step-by-step: Finding Where a Value Goes Wrong
  1. Identify the symptom — wrong value displayed, wrong API call, wrong UI state.
  2. Find the function responsible for producing the correct value.
  3. Set a line breakpoint at the start of that function.
  4. Reproduce the issue (click the button, submit the form, reload).
  5. When paused, read the Scopes panel — is the input data correct?
  6. Step Over each line, watching the Scopes panel update.
  7. The moment a variable becomes wrong, you've found the bug.
💡 Fastest Way to Find an Error's Origin Enable Pause on Exceptions (⬡ in the toolbar) before reproducing the error. The Debugger pauses the moment the exception is thrown — before any stack unwinding — with the Scopes panel showing exactly what state caused it. Far faster than reading a stack trace in the Console after the fact.
💡 Edit a Value to Test Your Fix While paused, double-click any value in the Scopes panel and type a new value. Press Enter. Resume execution — the program continues with your modified value. This lets you verify a fix in seconds without editing source, reloading, and reproducing the scenario.

✏️ Exercises

  • Browse the file tree. Open the Debugger (Ctrl + Shift + Z) on any site. How many JS files are listed? Press Ctrl + P and type a filename to use the file search.
  • Set a line breakpoint. Find an event handler (a button's click listener). Click its line number to add a blue breakpoint dot. Click the button on the page. When paused, read what's in the Scopes panel. Press F8 to resume.
  • Add a conditional breakpoint. Right-click a line inside a loop or function → Add Conditional Breakpoint. Enter an expression that will be true only for a specific case. Reproduce the action and confirm the Debugger only pauses when expected.
  • Use a logpoint. Right-click a line inside a loop → Add Log. Type a variable name or expression. Run the loop. Open the Console — you should see all the logged values without the Debugger ever pausing.
  • Practice stepping. With execution paused, press F10 (Step Over) several times. Watch the execution arrow move and the Scopes panel update. Then press F11 (Step Into) on a function call. Press Shift + F11 (Step Out) to return.
  • Enable Pause on Exceptions. Click the ⬡ icon in the Debugger toolbar. Navigate to a page with a JavaScript error in the Console. Reproduce the error — does the Debugger catch it before the Console does?
  • Blackbox a file. Right-click vendor.js, react.min.js, or any library file in the file tree → Ignore Source. Set a breakpoint in your own code that calls the library. Step through — confirm you never enter the library file.

📌 Key Takeaways

  • Line breakpoints pause unconditionally; conditional breakpoints (orange) only pause when an expression is true.
  • Logpoints (purple) log to the Console without pausing — use them for loops and frequent events.
  • Pause on Exceptions (⬡) catches errors the moment they are thrown, with full scope visible.
  • Step Over (F10) is the default; Step Into (F11) enters a function; Step Out (Shift+F11) exits one.
  • The Call Stack shows the full call chain — click any frame to inspect that context.
  • The Scopes panel shows every variable in scope with live values you can edit mid-execution.
  • Blackboxing keeps you in your own code by making the Debugger skip library files.
  • Source maps let you debug against original TypeScript/JSX even when the browser runs minified code.
Up next
Lesson 6 — The Storage Panel: inspecting and editing cookies, localStorage, sessionStorage, IndexedDB, and Cache Storage