# UI Fix Draft Pr

> Use when fixing any UI, CSS, or layout bug and producing a PR with visual evidence. Triggers when the user reports something looks broken on mobile or desktop (often with a screenshot), when you need before/after screenshots for a PR, when fixing Tailwind responsive issues, or when a layout overflows on certain viewports. Also use when the user says things like "fix this on mobile", "the layout is broken", "take a screenshot to verify", or "create a PR with screenshots". Covers diagnosis, fix, Playwright screenshot capture at mobile + desktop, image upload to GitHub without committing, and draft PR creation.

- Skill: `kilo-org/ui-fix-draft-pr` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add kilo-org/ui-fix-draft-pr`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kilo-org/ui-fix-draft-pr/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: Kilo-Org (https://skillmd.com/u/kilo-org)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kilo-org/ui-fix-draft-pr

---


# UI Fix with Playwright Screenshots

Fix a UI/layout issue and produce a draft PR with before/after Playwright screenshots at mobile and desktop viewports — images hosted on GitHub but never committed to the branch.

## Before Starting: Interactive or Autonomous?

Ask the user whether they want **interactive** or **autonomous** mode before doing anything else.

- **Interactive** — after applying CSS fixes (Phase 2), stop and show the `git diff` to the user. Wait for their feedback before proceeding to screenshots and PR. This lets the user request tweaks (spacing, alignment, which elements to show/hide at breakpoints) without needing to redo the entire screenshot → upload → PR cycle each time. Only move to Phase 3 once the user approves.
- **Autonomous** — run the full pipeline end-to-end without stopping: diagnose, fix, screenshot, upload, PR.

Default to interactive if the user doesn't specify — layout fixes often need a round or two of visual tuning that's hard to get right without feedback.

## Workflow

```
[Ask: interactive or autonomous?]
  → Read components → Diagnose root causes → Apply CSS fixes
  → (interactive? show diff, wait for approval)
  → Write Playwright test (mock API, capture before/after + desktop)
  → Upload screenshots to GitHub draft release
  → Commit code only, create draft PR with embedded images → Clean up
```

## Phase 1: Diagnose

Find the page component and read its tree. Compare what the user reports (screenshot, description) against the rendered layout. Common mobile overflow culprits:

| Symptom | Likely cause |
|---------|-------------|
| Page scrolls horizontally, content clipped on one side | A long unbreakable string (ID, hash, URL) forcing the page wider than the viewport |
| Buttons/tabs cut off at edge | Flex container without `flex-wrap` or `overflow-x-auto` |
| Two columns cramped on narrow screens | Missing `flex-col sm:flex-row` responsive stacking |
| Elements overlap or compress | Fixed widths that don't adapt, missing `min-w-0` on flex children |

## Phase 2: Fix

Apply minimal Tailwind class changes. Prefer the smallest diff that solves the problem — don't refactor surrounding code. Common fixes:

| Problem | Fix pattern |
|---------|------------|
| Long string overflows | `min-w-0 truncate` on the text element, `min-w-0` on its flex parent |
| Tabs/nav overflow | `overflow-x-auto` on the scrollable container |
| Side-by-side cramped on mobile | `flex flex-col gap-2 sm:flex-row sm:gap-4` |
| Buttons wrap awkwardly | `flex flex-col gap-2 sm:flex-row sm:flex-wrap` |

After fixing, verify TypeScript compiles with no new errors in the changed files.

## Phase 3: Playwright Test

Write a standalone `.spec.ts` test file rather than using Playwright MCP tools. Standalone tests are more reliable — MCP connections can time out during route mocking, and a test file is rerunnable and produces consistent results.

The test needs to render the real React components (not injected HTML) because Tailwind's JIT compiler only generates CSS classes that exist in the source code. Injected HTML uses classes the compiler never saw, so they render unstyled.

To render real components without a running backend, mock the API layer via `page.route()`. Read `references/playwright-template.md` for the full template and API mocking patterns (tRPC, REST, GraphQL).

The test file should capture:
1. **Mobile after** — screenshot at 375×812 with the fix applied
2. **Mobile before** — same page, then `page.evaluate()` to revert the CSS class changes on the live DOM, then screenshot (this reproduces the broken layout without needing to check out old code)
3. **Desktop** — screenshot at 1280×800 showing the layout works at full width
4. **Overflow assertion** — `scrollWidth <= clientWidth` for the fixed state, `scrollWidth > clientWidth` for the reverted state (quantifies the fix)

```bash
mkdir -p tests/e2e/screenshots
npx playwright test tests/e2e/your-test.spec.ts --project=chromium
```

### Compose Side-by-Side Images

After capturing screenshots, use `references/compose-screenshots.py` to create labeled before/after composites. These look much better in PRs than markdown tables — they have red/green "Before"/"After" labels and a dark background.

```bash
pip3 install --break-system-packages Pillow 2>/dev/null

python3 references/compose-screenshots.py \
  tests/e2e/screenshots \
  "Mobile (375x812):tests/e2e/screenshots/mobile-before.png:tests/e2e/screenshots/mobile-after.png"
```

This produces `side_by_side_mobile_375x812.png` in the screenshots directory. If you have multiple pairs (e.g. mobile + desktop before/after), pass them all and it also produces a stacked `all_comparisons.png`.

## Phase 4: Upload Screenshots to GitHub

Images belong in the PR description, not in the git history. Use a draft GitHub release as a free CDN — draft releases are hidden from the public but their asset URLs are permanent.

```bash
REPO="Owner/repo"
TOKEN=$(gh auth token)

# Create a hidden draft release to host images
RELEASE_ID=$(gh api repos/$REPO/releases \
  --method POST \
  -f tag_name="screenshots-temp-$$" \
  -f name="temp-screenshots" \
  -F draft=true -F prerelease=true \
  --jq '.id')

# Upload composed side-by-side image(s) and desktop screenshot
for img in tests/e2e/screenshots/side_by_side_*.png tests/e2e/screenshots/desktop.png; do
  [ -f "$img" ] || continue
  NAME=$(basename "$img")
  URL=$(curl -s \
    -H "Authorization: token $TOKEN" \
    -H "Content-Type: image/png" \
    --data-binary @"$img" \
    "https://uploads.github.com/repos/$REPO/releases/$RELEASE_ID/assets?name=$NAME" \
    | jq -r '.browser_download_url')
  echo "$NAME → $URL"
done
```

The upload host is `uploads.github.com`, not `api.github.com` — the `gh api` command doesn't handle binary uploads and returns 404 if you try. Use `curl` with `--data-binary`. Keep the draft release after uploading; deleting it breaks the asset URLs.

## Phase 5: Draft PR

Stage only the code changes. Create the PR with embedded `<img>` tags using the URLs from Phase 4.

Use the composed side-by-side image (from Phase 3) instead of a markdown table — it renders consistently across GitHub clients and looks much better:

```markdown
## Summary
- Bullet points describing each fix

## Mobile — Before vs After (375×812, Playwright)

<img src="SIDE_BY_SIDE_URL" width="800" />

## Desktop (1280×800, Playwright)

<img src="DESKTOP_URL" width="800" />

## Test plan
- [x] Playwright overflow assertion at mobile viewport
- [ ] Manual verification on device
```

## Phase 6: Clean Up

Remove the test file and screenshots directory — they were only needed to produce the PR evidence.

```bash
rm -f tests/e2e/your-test.spec.ts
rm -rf tests/e2e/screenshots
```

## Pitfalls

| Mistake | Why it happens | What to do instead |
|---------|---------------|-------------------|
| Mock with injected HTML | Seems faster, but Tailwind JIT won't generate classes for HTML that isn't in source files | Mock the API layer so real React components render |
| Use Playwright MCP for route mocking | MCP connections time out on long-running operations like route interception + page load | Write a `.spec.ts` file and run with `npx playwright test` |
| Commit screenshots to git | Images bloat the repo and trigger large-file warnings | Upload via draft release, reference URLs in PR body |
| Delete draft release after PR | Seems like cleanup, but asset URLs are tied to the release | Leave the draft release — it's hidden and harmless |
| Check out old branch for "before" | Slow, needs dependency reinstall, risks build failures | Render with fixed code, then `page.evaluate()` to strip fixes from the DOM |
| Missing API procedures in mock | Page hangs on loading spinner for queries that never resolve | Map every tRPC/REST/GraphQL call the page makes — return `null` data for non-essential ones |

