Locate UI from Code
Codex Compatibility
When running this skill in Codex, translate Claude Code-only primitives before acting: AskUserQuestion -> chat/request_user_input, TodoWrite -> update_plan, Task/TaskCreate/TeamCreate/SendMessage -> spawn_agent/send_input/wait_agent when available and allowed, and EnterPlanMode/ExitPlanMode -> a concise chat plan plus explicit approval.
Resolve Read/Write/Edit/Bash/WebSearch/WebFetch to Codex file/shell/web tools, and map ~/.claude/... paths to ~/.agents/... or ~/.codex/... unless the task explicitly targets Claude Code.
Cursor Compatibility
When running this skill in Cursor Agent, translate Claude Code-only primitives before acting: AskUserQuestion -> AskQuestion; TodoWrite -> Cursor TodoWrite or an equivalent checklist; Task/TaskCreate/TeamCreate/SendMessage/multi-agent flows -> Cursor Task (subagents), parallel Tasks, or run_in_background when allowed (TeamCreate/SendMessage may have no exact match); EnterPlanMode/ExitPlanMode -> Plan mode (SwitchMode / CreatePlan) plus explicit user approval.
Resolve Read/Write/Edit/StrReplace/Bash/web/search/MCP via Cursor Composer or Agent equivalents. MCP names written as mcp__server__tool typically map to call_mcp_tool with configured server identifiers. Map ~/.claude/... to ~/.cursor/skills/, .cursor/skills/, and .cursor/rules/ unless the task explicitly targets Claude Code.
Resolve two related questions in one workflow:
- Where does this code relate to the running app? (component mount point, surrounding UI, DOM)
- How do you reach the specified logic / branch in the live app? (user operations that make
debugger, anifbranch, auseEffect, or an event handler actually run)
The agent must execute the reach operations itself (not only describe them) and explain the recipe so the user can reproduce or attach DevTools at the right moment.
When to invoke
- "
<ComponentName>って画面上のどれ?" / "Where does<X>render?" - "
file.tsx:139のdebuggerにどう到達する?" / "What clicks get me into this branch?" - "
useEffectOnAnyのelseブロックを踏みたい" / "How do I trigger this handler?" - Code review / PR / bug report needs a visual anchor and the interaction path that reaches it
- Confirming what DOM a styled component collapses into
- Investigating why a selector matches multiple / zero elements
Inputs
Required (at least one):
- File path + line number (e.g.
@src/.../Foo.tsx:139) — preferred when user pins a line - React component name (e.g.
FolderHeader) - CSS selector / visible text / ARIA role + name
data-insp-pathor similar source-attribution attribute
Implicit: read surrounding code (±30 lines) to classify the target and derive preconditions.
Target classification (do this first)
| Kind | Code signals | Skill output focus |
|---|---|---|
| Render target | JSX return, styled component, className, visible t.* label |
DOM locator + on-screen highlight + screenshot of that element |
| Logic target | debugger, useEffect*, if/else, early return, event handler body, mutation onSuccess |
Reach recipe (operations agent ran) + screen state when branch fires + highlight nearest UI anchor |
If the pinned line is logic (e.g. debugger inside useEffect), do not stop at "this component renders on tab X". You must derive and run the operations that satisfy the branch guard.
Deriving a reach recipe (logic targets)
- Read the enclosing function / effect / handler.
- List every guard that must be true (e.g.
isChanged === true, modal open, API refetch completed). - For each guard, identify the user-visible action that flips it (DnD reorder, button click, form submit, tab switch).
- Order steps by dependency (e.g. reorder before create-item refetch).
- Note account / role / seed data if guards depend on permissions or existing rows.
- Execute the sequence in the browser; re-snapshot after each step that changes guards.
Example guard → action mapping:
| Guard in code | User operation |
|---|---|
isChanged === true |
Drag an item between columns or reorder within a list without saving |
orderItemSettings updates while isChanged |
Complete "新規項目追加" (or any action that invalidates the query) after step above |
isOpen && step === 2 |
Open modal → pick type on step 1 → advance |
role !== 'admin' |
Log in as the non-admin test account from project docs |
Workflow (6 phases)
Phase 1 — Identify target in code
- Open the file at the pinned line (or grep component name).
- Classify render vs logic (see table above).
- Walk up render parents to the page route → URL path.
- For render targets: pick a runtime locator (text,
aria-*,data-testid,data-insp-path). - For logic targets: write the reach recipe draft (guards + ordered UI steps) before opening the browser.
grep -rn "FolderHeader" --include="*.tsx" -l
# definition + usages -> trace to the page route
If the project ships data-insp-path="<file>:<line>:<col>:<Component>", prefer it for render targets.
Phase 2 — Open the browser at the right state
Browser mode (mandatory)
Default: headed / visible. The user must be able to follow along and attach DevTools.
| Environment | Primary | Notes |
|---|---|---|
| Claude Code (chrome-devtools MCP) | chrome-devtools MCP | --headed equivalent via MCP |
Cursor (zumen-fe and repos with cursor-specific.mdc) |
cursor-ide-browser MCP |
playwright-cli unless user explicitly requests it |
| Cursor (generic) | cursor-ide-browser if available, else playwright-cli --headed |
|
| Codex CLI / shell | playwright-cli --headed |
# playwright-cli (when allowed)
playwright-cli open https://local.zume-n.com/ --headed
playwright-cli state-load .auth.json # after one-time login + state-save
Cursor IDE browser flow:
kill-port 8080→ start dev server if needed (pnpm dev -p 8080).browser_tabs(list) →browser_navigateto landing / login URL.browser_lock→ operate → leave open (see Phase 6).
Respect project rules. If the repo forbids URL direct navigation after login (正規動線のみ), navigate by clicking nav / sidebar / tabs — not goto to deep paths.
Use project auth: .agent_browser, test_accounts_and_permissions, or Serena memory.
Phase 3 — Navigate to the screen
Follow 正規動線 to the page that hosts the component:
- Login (if needed).
- Top nav → settings (or equivalent).
- Side nav / tabs to the feature screen.
- Activate the correct tab / panel / accordion.
Snapshot after arrival; confirm URL and key labels match expectations.
Phase 4 — Execute reach operations (logic targets: mandatory)
For logic targets, this phase is not optional. Perform each step in the reach recipe:
- Snapshot → locate refs for buttons, drag handles, tabs.
- Execute clicks, fills, tab switches.
- For dnd-kit / custom DnD: do not trust ref-only
dragsuccess. Use coordinate pointer ops (browser_get_bounding_box→ move → mousedown → move → mouseup) per projectbrowser-dnd-coordinate-qarules. Verify list order / column changed in snapshot text. - After the final step, snapshot again and confirm guards plausibly hold (e.g. save button enabled = dirty state, new row visible = refetch happened).
- If the line is
debugger: leave the browser on that screen state and tell the user "DevTools open + resume once — next refetch/render will pause here." Do not remove the user's breakpoint.
For render targets only: skip to Phase 5 once the element is visible (tabs expanded, scrolled into view).
Phase 5 — Locate element + highlight + capture evidence
playwright-cli snapshot
# or browser_snapshot in Cursor
When multiple candidates exist, enumerate with eval / CDP:
playwright-cli --raw eval "() => Array.from(
document.querySelectorAll('[data-insp-path*=\"FolderHeader\"]')
).map((el, i) => ({ i, text: el.textContent.slice(0, 40), rect: el.getBoundingClientRect().toJSON() }))"
On-screen highlight (mandatory when target is visible)
If the target (or nearest UI anchor for a logic target) is on screen, highlight it before / with the screenshot. A brief tool flash alone is not enough — the user must see a clear ring + file-name badge.
- Resolve the DOM node (prefer
data-insp-path, thenaria-label/role, then visible text). - Inject the persistent overlay from
references/highlight-overlay.md(red ring +Foo.tsxbadge + optional locator subtitle + page dim). - Also call
browser_highlighton the snapshot ref when using Cursor (extra pulse). - Screenshot the viewport with the overlay visible as
<name>_highlighted.png. - Leave the overlay on (do not auto-remove). Tell the user: reload clears it, or ask the agent to remove
#__locate-ui-highlight-root.
Skip only when the target truly cannot appear (unreachable permission, headless-only failure). Say so explicitly in the report.
Capture in parallel:
- Highlighted screenshot — full viewport with overlay (preferred for presentation).
- Element screenshot — optional close-up when useful.
- DOM dump —
outerHTML(~600 chars), rect, key computed styles, a11y attrs, 1-level children.
Save path priority:
.claude/tasks/assets/<task>/spec_reference/docs/screenshots/ordocs/images/<repo-root>/screenshots/<name>_visual.pngand<name>_highlighted.png
Naming: <component-or-branch-purpose>_visual.png / _highlighted.png — never screenshot.png.
Phase 6 — Save & present
Always present (logic targets):
- Target classification — render vs logic; quote the pinned lines and branch condition in plain language.
- Reach recipe — numbered list of operations the agent already ran (account, nav path, clicks, DnD). Mark which step flips each guard.
- DevTools note (if
debugger/ breakpoint) — when execution pauses relative to the last user action. - Screen location — URL, Japanese screen name, tab name, 正規動線 one-liner.
Also present when applicable:
- Visual — embed highlighted screenshot (ring + file badge); plain visual as backup
- Highlight note — what was outlined and how to clear the overlay
- Elements tree — truncated
outerHTML - Computed styles — small table
- Children map — 1-level preview
- A11y attributes
- Source mapping — decode
data-insp-path
Keep the browser open (do NOT close it)
End with the browser on the state where the branch is reachable (logic) or on the located element (render):
- Never
playwright-cli close/browser_closeas cleanup. - Leave the highlight overlay on (
#__locate-ui-highlight-root) so the user can inspect live. - Tell the user the window is open for DevTools / inspection.
- Close / clear highlight only on explicit user request or session recovery.
Pitfalls
- Stopping at component mount — a line inside
useEffectis not "the whole tab"; explain and run the trigger sequence. - Wrong guard order — e.g. creating an item before setting
isChangedmay never enter theelsebranch you want. - Headless by default (playwright-cli) — always headed for this skill.
- Auth redirect loops —
state-save/state-loador project login URL (https://local.zume-n.com, not rawlocalhost:8080when Auth0 callback requires it). - DnD false success — verify rendered order/group changed, not just tool exit code.
- Lazy / collapsed UI — expand tabs and scroll before snapshot.
- Skipping highlight — if the target is visible, always draw the overlay + save
_highlighted.png; do not end with only a plain screenshot. - Token budget — truncate
outerHTML; full dumps go to files. - Ref drift — re-snapshot after every navigation or DOM-changing action; re-apply overlay after DOM-changing steps if the ring drifts.
- Cursor vs playwright — follow repo browser rules; zumen-fe uses
cursor-ide-browserby default.
See also
references/highlight-overlay.md— mandatory on-screen highlight recipe (ring + file badge)references/tool-equivalents.md— MCP / playwright-cli command translationreferences/example-walkthrough.md— render target example (FolderHeader)references/example-logic-branch-reach.md— logic target example (debuggerinuseEffectelse branch)