Home / Guides / Mobile adaptation

Adapting blocks and patterns for mobile

Four breakpoints, predictable changes, no per-page media queries. Once you know the rule for each block, the page falls out automatically.

Guide 4 breakpoints Before / after examples

Breakpoint conventions

Four named breakpoints, each with one job. Don't introduce new ones.

TokenWidthWhat happens
--bp-toc1280pxTOC sidebar hides. Article goes full width. The first thing to go on smaller laptops.
--bp-nav1100pxTop nav collapses into the brand row. Search shrinks to an icon.
--bp-drawer900pxSidebar becomes a drawer behind a menu toggle. Two-column layouts stack.
--bp-phone720pxFull phone treatment — bottom nav, bottom sheets, card-list tables, segmented controls become selects.

The pattern: each block declares its own rule at each breakpoint. The page never adds media queries — only blocks do. If your page needs a media query, the underlying block is missing one.

Block-by-block adaptation rules

What each block does at < 720px. The full responsive plan lives on each block's own doc; this is the cheat sheet.

BlockPhone treatment
Page headerTitle, lede, and actions stack vertically. Primary action moves below the lede; secondary actions collapse into a "⋯" menu.
Data toolbarSearch row on top. Filter chips become a horizontally scrolling row with momentum scroll — no wrapping.
Data tableBecomes a card list. Each row is a mobile list item with the most important 2–3 columns; the rest are revealed on tap.
Settings shell240px section rail becomes a top-level select with all section names; chosen section renders below.
ModalCentered modal becomes a bottom sheet with a drag handle. Backdrop fades; sheet swipes to dismiss.
KPI grid4-up grid becomes 2-up at 900px and 1-up at phone. Cards keep their full content; no truncation.
Form shellSticky action bar becomes a bottom-anchored Mobile action bar with the primary action filling the width.
Detail heroTwo-column hero stacks. Primary action becomes a sticky bottom button. Secondary facts collapse to a "More" expander.

Pattern-level rules

Patterns own larger transitions — whole navigation models change.

PatternPhone treatment
App shellSidebar disappears entirely. Up to 5 top-level destinations live in a bottom nav (see portal-shell.css .ps-tabbar).
Detail + tabsTab strip becomes a segmented control if 2–4 tabs, or a select if 5+. Active tab body fills the rest of the screen.
Detail viewTwo-column hero + summary rail becomes a single column with the summary collapsed below a "Details" header.
Command paletteFull-screen modal with on-screen keyboard awareness. ⌘K shortcut hidden; surface is reachable from a search icon in the app bar.
Bulk editBulk action bar moves from sticky-top to sticky-bottom — thumb-reachable.
Import wizardSteps collapse from horizontal stepper to a single "Step 2 of 4" indicator above the active step content.

Before / after — four components

Each pair shows the desktop arrangement on the left and the phone treatment on the right.

1 · App shell → bottom nav

Desktop · ≥ 900px

huchu.app/retail
Home Orders Returns Customers Reports
Park Centre · today
Sales
ZWG 18,290 · 142 orders

Sidebar lists every destination. Topbar carries breadcrumb and global actions.

Phone · < 720px

Retail
Sales
ZWG 18,290
Orders
142 today

Sidebar gone. Five top-level destinations sit in a thumb-reachable bottom nav.

2 · Data table → card list

Desktop · ≥ 900px

huchu.app/orders
Orders · 142
Open Overdue Draft
ORD-1042Mai TendaiZWG 240Open
ORD-1041NetOne LTDZWG 1,820Open
ORD-1040Park CentreZWG 90Paid

Full table with sortable columns, sticky header, and inline status.

Phone · < 720px

Orders
Open Overdue Draft
ORD-1042 · ZWG 240
Mai Tendai · Open
ORD-1041 · ZWG 1,820
NetOne LTD · Open
ORD-1040 · ZWG 90
Park Centre · Paid

Each row becomes a card. Two most-important columns in title; the rest in the subtitle. Tap reveals more.

3 · Modal → bottom sheet

Desktop · ≥ 900px

huchu.app/refund
Issue refund
ZWG 240 to original payment method.
Cancel Refund

Centered modal with backdrop. Focus trapped, Esc closes, return-focus on dismiss.

Phone · < 720px

Order ORD-1042
Line items
3 lines · ZWG 240
Issue refund
ZWG 240 to original method.
Cancel Refund

Sheet rises from the bottom with a drag handle. Swipe-down dismisses. Primary action sits at thumb height.

4 · Settings rail → top select

Desktop · ≥ 900px

huchu.app/settings
Profile Notifications Branches Integrations Billing
Notifications
Email digest
Daily at 7am
SMS alerts
For overdue invoices only

240px rail of sections on the left; scroll-spy highlights the active one.

Phone · < 720px

Settings
Notifications
Email digest
Daily at 7am
SMS alerts
For overdue invoices only

Rail collapses into a top-level select; chosen section renders below. No horizontal split on phone.

Bonus · Detail tabs → segmented control

Tab strips above 4 tabs become a select; 2–4 stay as segmented controls.

Desktop · ≥ 900px

huchu.app/cus_8a32
Mai Tendai · cus_8a32
Overview Orders Payments Activity
Last order
ORD-1042 · 3 days ago

Tabs are an underlined strip — full names visible.

Phone · < 720px

Mai Tendai
OverviewOrdersPaymentsActivity
Last order
ORD-1042 · 3 days ago

Strip becomes a segmented control. At 5+ tabs, it becomes a select instead.

"Test on a phone" checklist

Run through this before merging anything that touches a product surface.

  • Open the page on a real phone (or DevTools at 375×812). Don't trust the responsive preview in your IDE.
  • Every primary action is reachable with one thumb without scrolling.
  • No horizontal scroll anywhere except the explicitly-scrollable filter chip row.
  • Tap targets are at least 44×44px. Stack adjacent buttons rather than crowding them.
  • Bottom nav is visible if the page is part of a portal. Page header doesn't hide behind it.
  • Forms: the keyboard doesn't cover the active input. Sticky action bar sits above the keyboard.
  • Modals are bottom sheets with a drag handle. Backdrop tap dismisses; Esc dismisses on hardware keyboard.
  • Tables render as card lists. The "most important two" columns are in the card title; the rest are revealed on tap.
  • Loading and empty states render correctly on phone too — check both.
  • Pinch-zoom works (never set user-scalable=no). Long-press shows the system context menu on text.

Do & don't

Do

Put media queries inside blocks, never on pages. The page just composes blocks and inherits their responsive behavior.

Don't

Add a new breakpoint to fix one page. Adapt the misbehaving block at an existing breakpoint instead.

Do

Test on a real phone before merging. Browser DevTools lie about touch behavior, sheet gestures, and on-screen keyboards.

Don't

Hide secondary actions behind a "⋯" menu on desktop. Reserve overflow menus for phone.

Do

Make the primary action thumb-reachable on phone — bottom-anchored, full-width if necessary.

Don't

Disable pinch-zoom. Operators rely on it to read small numbers and codes; the system supports it everywhere.

What's next

For the full mobile component catalogue, see Mobile list, Mobile action bar, and the portal shells in portal-shell.css.