One Claude Code Tip a Day: Verify the UI Before You Call It Fixed

A field guide to using Claude Code for frontend fixes: make it reproduce the bug, inspect the DOM, verify in the browser, and correct the patch before declaring done.

Abstract developer workstation showing code, terminal logs, tests, and a browser preview being verified

This post is part of the “One Claude Code Tip a Day” series — a daily guide to using Claude Code more effectively.

The real failure: a fix that only exists in the diff

Frontend work is where Claude Code can sound finished before the product is fixed. A common session goes like this: you report that a mobile menu will not close, Claude finds a likely CSS selector, edits a component, and the test suite stays green. The diff looks reasonable. Then you open the page and the menu still covers the screen because the state class is on `body`, not on the header element Claude patched.

Today's habit is to treat the browser as the final authority. Do not let a clean diff, a passing unit test, or a confident summary end the loop. Use Claude Code to build a verification trail: reproduce the bug, identify the visible symptom, inspect the actual DOM or logs, patch the smallest surface, and then re-check the interface before you accept the answer.

Start with a reproduction contract

Before editing, make Claude write down how the bug will be observed. A good opening prompt is:

`We need to fix the mobile settings drawer that remains open after tapping Save. Do not edit yet. Read the relevant component, route, styles, and tests. Tell me the exact reproduction steps, the state/classes/events you expect to change, and the smallest browser or test check that would prove the fix.`

This prompt prevents the lazy version of AI coding: searching for a phrase, patching the first match, and calling it done. You are asking Claude to connect source code to user-visible behavior. If it cannot explain what should change on screen, it is not ready to edit.

Use Claude Code as the verification driver

Once Claude has a theory, give it permission to use tools, but keep the scope narrow:

`Patch only the drawer close behavior. After the edit, run the relevant unit test if one exists. Then start the local app or tell me the exact command to run. Inspect the browser result: confirm the drawer closes, focus returns to the trigger, and no console error appears.`

In a real session, that may translate to `npm test -- settings-drawer`, `npm run dev`, a hard refresh, and checking the rendered class list. If browser automation is available, Claude can inspect the DOM directly. If it is not, make it produce a manual checklist precise enough for you to execute: viewport, route, click path, expected class removal, expected network response, and console state.

Do not skip the evidence pass

After the first patch, ask for evidence rather than a victory lap:

`Show me the verification evidence. Include the command output, the files changed, the before/after behavior, and any browser or console observations. If any step was not actually run, label it as not run instead of implying success.`

This wording matters. Claude Code is useful when it distinguishes observed facts from intended outcomes. A good answer might say, ‘Unit test passed, browser not run because dev server failed on port 3000.’ That is not a failure of the assistant; it is a useful stop sign. Now you know the loop is incomplete.

Second-pass correction: when the UI still fails

The second pass is where this habit earns its keep. Suppose the drawer still stays open. Do not say, ‘try again’ and hope for magic. Hand Claude the failed observation:

`The test passed, but in the browser the drawer remains visible. Current DOM after Save: body has class modal-open; #settings-drawer is aria-hidden=false; console has no error. Re-read the event flow and styles. Do not broaden the patch until you explain why the first fix did not affect the rendered state.`

Now Claude has to reconcile code with reality. It may discover that the component updates React state, but a body scroll-lock helper owns the visible class. Or it may find that desktop and mobile styles have separate media-query blocks. The point is not that Claude guesses better on the second try; the point is that the second try is constrained by evidence from the running UI.

Failure modes to watch for

First, beware of test-only confidence. Unit tests can prove a callback fired while the visible drawer remains open because CSS, focus traps, portals, or body classes are outside the test boundary.

Second, beware of selector mismatch. Claude may patch `.drawer.open` while the live DOM uses `[data-state=open]`, a generated class, or a class on an ancestor. Ask it to inspect rendered markup before changing CSS.

Third, beware of dev-server drift. If the browser is showing an old build, every source patch will look ineffective. Make Claude check the running command, terminal logs, cache behavior, and whether a hard refresh or rebuild is required.

Rule of thumb

For frontend work, never accept ‘fixed’ until Claude Code can name the user-visible behavior, the code path that controls it, the verification command or browser check, and the evidence from the second pass if the first patch failed. The diff is a hypothesis. The browser is the verdict.