mobile-debugging
Patterns for debugging mobile-specific issues on iOS Safari and Android Chrome. Use this skill when encountering viewport, keyboard, or touch-related bugs that only reproduce on real mobile devices. Don't use for general debugging (use /playbook:debug instead), or for desktop browser issues.
What this skill does
# Mobile Debugging
This skill provides patterns for debugging mobile-specific issues, particularly viewport and keyboard handling differences between iOS Safari and Android Chrome.
## When to Use This Skill
Use this skill when:
- Bugs only reproduce on real mobile devices (not emulators)
- Issues involve keyboard appearance/dismissal
- Problems with viewport sizing or scrolling
- Overscroll or bounce behavior issues
- Touch input behaves differently than expected
## Critical Insight: Real Devices Required
**Many mobile bugs cannot be reproduced in:**
- Browser developer tools device emulation
- Playwright/Puppeteer automated tests
- iOS Simulator or Android Emulator
**Always test on real physical devices** for:
- Keyboard viewport resizing
- Overscroll/bounce behavior
- Touch gesture nuances
- Safari-specific viewport handling
### Testing Setup Recommendations
1. **Local device testing**: Use ngrok to expose localhost
2. **Preview deployments**: Deploy to Vercel/Netlify preview
3. **Multiple devices**: Test on both iOS (Safari) and Android (Chrome)
## Platform Behavior Differences
iOS Safari and Android Chrome handle viewports completely differently:
| Behavior | Android Chrome | iOS Safari |
|----------|---------------|------------|
| `interactiveWidget: resizes-content` | ✅ Resizes viewport | ❌ Ignored |
| `100dvh` on keyboard open | ✅ Shrinks correctly | ⚠️ Layout viewport unchanged |
| `scrollIntoView()` with keyboard | ✅ Works immediately | ❌ Needs 350ms delay |
| Keyboard dismiss detection | Via resize event | Via focusout/blur |
| Overscroll prevention | `overscroll-behavior` works | May need additional handling |
**Key Implication**: CSS-only solutions (`dvh` units, viewport meta) work on Android but require JavaScript workarounds on iOS Safari.
## Common Mobile Bug Patterns
### Pattern 1: Input Covered by Keyboard (iOS Safari)
**Symptom**: When focusing an input, the keyboard covers it instead of scrolling into view.
**Root Cause**: iOS Safari doesn't resize the layout viewport when the keyboard appears.
**Solution**: Add `scrollIntoView` on focus with delay:
```typescript
const handleFocus = () => {
// Wait for iOS keyboard animation (~300ms)
setTimeout(() => {
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
}, 350);
};
```
**Apply to**: All inputs that could be near the bottom of the screen (chat inputs, login forms, comment boxes).
### Pattern 2: Gray Space Below Content
**Symptom**: User can scroll past content to reveal gray/white space below.
**Root Cause**: Usually a wrapper element with `min-h-screen` or `min-height: 100vh` that extends beyond the viewport.
**Debugging Steps**:
1. Check `layout.tsx` or root layout for wrapper divs
2. Look for `min-h-screen`, `min-h-full`, or `min-height` properties
3. Check if body has `overflow: auto` instead of `overflow: hidden`
**Solution**:
```css
/* globals.css */
html, body {
height: 100%;
overflow: hidden;
overscroll-behavior: none;
}
```
**And**: Remove wrapper divs with `min-h-screen`. Let pages handle their own height with `h-dvh`.
### Pattern 3: Flex Layout Not Filling Height
**Symptom**: Components don't fill available vertical space properly.
**Root Cause**: Broken flex layout cascade - using `h-full` instead of `flex-1`.
**Solution**: Ensure flex layout cascades through component tree:
```tsx
// ❌ Wrong
<View className="flex-1">
<ChildComponent className="h-full" /> {/* Won't fill properly */}
</View>
// ✅ Correct
<View className="flex-1 flex flex-col">
<ChildComponent className="flex-1" /> {/* Fills remaining space */}
</View>
```
### Pattern 4: Textarea Doesn't Shrink
**Symptom**: After deleting all text (select all + delete), textarea stays expanded.
**Root Cause**: `scrollHeight` doesn't immediately reflect empty content.
**Solution**: Explicitly check for empty value:
```typescript
const adjustHeight = () => {
if (!value || value.length === 0) {
element.style.height = `${minHeight}px`;
return;
}
// ... normal scrollHeight calculation
};
```
### Pattern 5: Overscroll Bounce
**Symptom**: Page bounces when scrolling past content edges.
**Solution**:
```css
body {
overscroll-behavior: none;
}
```
For scroll containers:
```tsx
<ScrollView
bounces={false} // iOS
overScrollMode="never" // Android
/>
```
## Debugging Checklist
When encountering a mobile-specific bug:
### Step 1: Get Real Device Evidence
- [ ] Screenshot from real iOS device (Safari)
- [ ] Screenshot from real Android device (Chrome)
- [ ] Confirm bug doesn't reproduce in browser dev tools
### Step 2: Check Root Layout First
- [ ] Check viewport meta tags in `layout.tsx`
- [ ] Look for `min-h-screen` wrappers
- [ ] Verify `overflow: hidden` on html/body
- [ ] Check for `interactiveWidget` setting
### Step 3: Check Component Layout
- [ ] Verify flex layout cascades properly (`flex-1` not `h-full`)
- [ ] Check for fixed heights that might conflict
- [ ] Look for unnecessary scroll containers
### Step 4: Platform-Specific Checks
- [ ] For iOS keyboard issues: Add `scrollIntoView` with 350ms delay
- [ ] For Android keyboard issues: Verify `interactiveWidget: resizes-content`
- [ ] For overscroll: Add `overscroll-behavior: none`
## Viewport Meta Tag Reference
```tsx
// layout.tsx
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
maximumScale: 1, // Prevents zoom on input focus
// Android: Make keyboard resize viewport instead of overlay
interactiveWidget: 'resizes-content',
};
```
## Testing requestAnimationFrame in Jest
If your mobile fix uses `requestAnimationFrame`, tests may fail because Jest doesn't execute rAF callbacks synchronously.
**Solution**: Mock rAF in tests:
```typescript
beforeEach(() => {
jest.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => {
cb(0);
return 0;
});
});
afterEach(() => {
jest.restoreAllMocks();
});
```
## References
- [MDN VisualViewport API](https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport)
- [Chrome Viewport Resize Behavior](https://developer.chrome.com/blog/viewport-resize-behavior)
- [iOS Safari Keyboard Detection](https://martijnhols.nl/blog/how-to-detect-the-on-screen-keyboard-in-ios-safari)
- [CSS-Tricks Auto-Growing Textareas](https://css-tricks.com/the-cleanest-trick-for-autogrowing-textareas/)
## Summary
Mobile debugging requires:
1. **Real devices** - Emulators don't reproduce many bugs
2. **Platform awareness** - iOS Safari ≠ Android Chrome
3. **Root-level checks first** - Viewport meta, body overflow, wrapper elements
4. **JavaScript workarounds for iOS** - `scrollIntoView` with delays
## Integration with Playbook
This skill works with:
- `/playbook:debug` - Use this skill during mobile debugging sessions
- `/playbook:learnings` - Capture mobile-specific fixes for future reference
- `debugging-agent` - Provides mobile-specific debugging patterns
---
*When in doubt: check on a real device, check the root layout, and remember iOS Safari needs special handling.*
Related in Code Review
gstack
IncludedFast headless browser for QA testing and site dogfooding. Navigate pages, interact with elements, verify state, diff before/after, take annotated screenshots, test responsive layouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or test a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)
startup-due-diligence
IncludedLegal due diligence review for seed-stage and Series A startups (US, Delaware C-Corp focus). Supports both investor and founder perspectives. Capabilities include: (1) Interactive document review and issue spotting; (2) Document request list generation; (3) Cap table and SAFE/convertible note analysis; (4) Red flag identification with severity ratings; (5) Diligence report generation. TRIGGERS: due diligence, DD, startup investment, cap table review, Series A, seed round, investor diligence, legal review startup, SAFE analysis, convertible note, 409A, founder vesting.
interview-master
IncludedThis skill should be used when the user asks to "generate interview questions", "prepare for interview", "optimize resume", "conduct mock interview", "analyze git commits for resume", "generate resume from code", "review my resume", or mentions interview preparation, career assistance, or extracting project experience from git history. Provides comprehensive interview and career development guidance for both job seekers and interviewers.
fix-issue
IncludedFixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection. Reads issue context from gh CLI, searches codebase and memory for related patterns, generates a fix with tests, and links the resolution back to the issue via PR. Includes prevention analysis to avoid recurrence. Use when debugging errors, resolving regressions, fixing bugs, or triaging issues.
sf-apex
IncludedGenerates and reviews Salesforce Apex code with 150-point scoring. TRIGGER when: user writes, reviews, or fixes Apex classes, triggers, test classes, batch/queueable/schedulable jobs, or touches .cls/.trigger files. DO NOT TRIGGER when: LWC JavaScript (use sf-lwc), Flow XML (use sf-flow), SOQL-only queries (use sf-soql), or non-Salesforce code.
swift-development
IncludedComprehensive Swift development for building, testing, and deploying iOS/macOS applications. Use when Claude needs to: (1) Build Swift packages or Xcode projects from command line, (2) Run tests with XCTest or Swift Testing framework, (3) Manage iOS simulators with simctl, (4) Handle code signing, provisioning profiles, and app distribution, (5) Format or lint Swift code with SwiftFormat/SwiftLint, (6) Work with Swift Package Manager (SPM), (7) Implement Swift 6 concurrency patterns (async/await, actors, Sendable), (8) Create SwiftUI views with MVVM architecture, (9) Set up Core Data or SwiftData persistence, or any other Swift/iOS/macOS development tasks.