Skip to main content
AC
Build & Implementation4.7 KBMIT licensed

mobile-first-responsive

Original, written for TechTide client work

Build and audit mobile-first responsive UI in React + Tailwind + shadcn/ui. Use when creating any new page or surface, or when the user says "mobile", "responsive", "touch", "breakpoints", "safe area", "works on phones", or reports a phone-only layout bug. Not for desktop-only admin consoles (confirm that scope first), and not for 3D canvas tuning: use build-3d-website.

  • mobile
  • first
  • responsive

SKILL.md

Mobile-First Responsive Build

Build for a 375px phone first, then enhance upward. Most shipped apps get opened on a phone, so a layout that only resolves at desktop width is unfinished, not "responsive later."

When this applies

  • Any new page, route, or major UI surface, public or authenticated.
  • Any bug report shaped like "broken on my phone", "horizontal scroll", "button too small", "hidden by the notch", "keyboard covers the input".

Skip only for surfaces the user has explicitly confirmed as desktop-only. Do not assume desktop-only.

Workflow

  1. Set the preview to 375 x 667 before writing layout. Compose the whole screen at that width with zero horizontal scroll.
  2. Add sm: / md: / lg: enhancements upward. Never start at desktop and shrink.
  3. Apply the hard rules below while building, not after.
  4. Run the self-audit before declaring done. Read references/mobile-audit-checklist.md when you reach verification or when debugging a phone-only bug.

Hard rules

RuleWhy
Base Tailwind classes target the phone; sm:+ only addlg: defaults with mobile overrides invert the model
No element wider than the viewportFixed px widths, w-screen, whitespace-nowrap, and unbroken strings cause it
min-w-0 on flex/grid children holding textFlex children refuse to shrink without it; the #1 overflow bug
Touch targets at least 44 x 44px (min-h-11 min-w-11), 8px apartBelow that, taps miss
h-dvh / min-h-dvh, never h-screen100vh is wrong on mobile Safari and Chrome URL-bar math
Body text 16px minimum, inputs 16px minimumSmaller triggers iOS input zoom
viewport-fit=cover plus env(safe-area-inset-*) padding on fixed barsContent hides under the notch or home bar otherwise
Every animation has a prefers-reduced-motion: reduce fallbackMotion sensitivity is an accessibility requirement
Never set maximum-scale=1 or user-scalable=noBlocking pinch-zoom is an a11y failure

Touch ergonomics

  • Primary actions in the bottom two thirds of the screen, thumb reach.
  • Correct type / inputmode on inputs so the right keyboard opens.
  • No hover-only affordances. :hover does not exist on touch. Add tap-visible equivalents and active: states.
  • touch-action: manipulation on interactive elements kills the 300ms tap delay.
  • Bottom-fixed CTAs must not sit under the on-screen keyboard when an input is focused.

Performance and accessibility

Assume slow network and weak CPU. Responsive images with dimensions set, lazy-load below the fold, defer heavy sections, cap canvas DPR at 2. Semantic landmarks, one <h1> per route, aria-label on icon-only buttons, contrast 4.5:1 for body text. Full lists live in references/mobile-audit-checklist.md.

Good vs bad

Good: a card row written as flex flex-col gap-3 md:flex-row, children carry min-w-0, buttons are min-h-11.

Bad: flex flex-row lg:gap-6 with a hidden lg:block sidebar and a w-[420px] card, then patching with overflow-x-hidden on body. Hiding the scrollbar does not fix the layout, it hides the evidence.

Verification

Do this: render the page at a real 375px viewport (device emulator or screenshot tool) and run the counts in references/mobile-audit-checklist.md. Expect every count to be 0 and no horizontal scroll. If any count is above 0, fix the finding and re-render. Desktop screenshots do not count as verification.

Completion checklist

  • [ ] Built and verified at 375px before any desktop pass
  • [ ] All audit counts in references/mobile-audit-checklist.md are 0
  • [ ] Fixed bars padded with safe-area insets
  • [ ] Inputs have correct type / inputmode and 16px font
  • [ ] Reduced-motion fallback on every animation

Any box unchecked: not done. Fix or say so.

Footguns

  • h-screen on a full-height hero: bottom content sits under the mobile URL bar. Fix: min-h-dvh.
  • Text overflowing a flex row: the child lacks min-w-0. Fix: add min-w-0 and break-words, not a hardcoded width.
  • Bottom nav floating above the home indicator gap, or under it: missing pb-[env(safe-area-inset-bottom)] plus viewport-fit=cover in the viewport meta. Both are required together.
  • iOS zooms on input focus: input font-size below 16px. Fix the font size, do not disable zoom.

Reference files

More in Build & Implementation

All skills