Demo

How to make mobile responsive

Detect mobile with useMediaQuery(SCREENS.md), keep one data source, and switch desktop DataTable + PageTitle for mobile cards + FAB — never hide features on small screens.

Goal

Ship list/detail pages that feel dense and efficient on desktop, and readable and thumb-friendly on mobile — without dropping capabilities on small screens.

  • One query / data source; branch presentation only
  • Desktop — DataTable + PageTitle actions
  • Mobile — card list + Floating action button for primary actions
  • Transform UI; do not hide features behind empty placeholders

1. Prerequisites

You need a plugin page that already loads data (React Query hook or equivalent) and uses shared UI primitives.

  • @quan-erp/shared-ui available (useMediaQuery, SCREENS, DataTable, PageTitle, PageContent)
  • A working list page with columns / rows for desktop
  • Optional: bottom nav configured if the page appears on mobile chrome

2. Detect mobile

Use the shared breakpoint helper. SCREENS.md is the standard Quark ERP mobile/desktop split for plugin pages.

  • isMobile === true below the md breakpoint
  • Prefer this over ad-hoc window.innerWidth checks
TSXisMobile
import { useMediaQuery, SCREENS } from "@quan-erp/shared-ui"; const isMobile = useMediaQuery(SCREENS.md);

3. Switch layout (same data)

Fetch once. Pass the same data / isLoading into both branches. On mobile, simplify or omit the dense PageTitle action row and move primary actions to a FAB.

  • Desktop — keep DataTable density and toolbar actions in PageTitle
  • Mobile — card list component; primary create/edit via FAB
  • Do not run a second query only for mobile
JSONtitle + content
1{isMobile ? ( 2 <div /> 3) : ( 4 <PageTitle> 5 <div className="flex items-center justify-between w-full"> 6 <span>{translation.get("feature", "Feature")}</span> 7 <Button onClick={() => setCreateOpen(true)}>Add</Button> 8 </div> 9 </PageTitle> 10)} 11 12<PageContent> 13 {isMobile ? ( 14 <MobileListView data={data} isLoading={isLoading} /> 15 ) : ( 16 <DataTable columns={columns} data={data} /> 17 )} 18</PageContent>

4. Mobile card pattern

Prefer cupertino-style cards so rows stay tappable and readable. Row actions use ghost icon buttons instead of dense table action columns.

  • Card shell — bg-card, p-4, rounded-3xl, cupertino-corner, border, shadow-sm, flex flex-col gap-3
  • Show the fields users need to decide; open a sheet/dialog for the rest
  • Keep edit / delete / status actions reachable — move them into the card or a detail sheet, do not drop them

5. Pull to refresh & bottom nav

Mobile lists should refetch with Pull to refresh. If the page sits in the bottom nav, shift FABs so they clear the bar.

  • Wrap mobile lists with Pull to refresh when users expect pull-down refetch
  • FAB position — bottom-25 when bottom nav visible; bottom-5 when hidden (see FAB how-to)
  • useIsContainInBottomNavBar(`/${metadata.name}/…`) from @quan-erp/base-frontend

6. Verify

Resize the browser or use device mode and confirm both presentations share the same records and actions.

  • Wide viewport — DataTable + PageTitle actions visible
  • Narrow viewport — card list + FAB; no empty “not available on mobile” stubs for core features
  • Create / edit / delete still reachable on mobile
  • Pull to refresh updates the same list data
  • With bottom nav visible, FAB clears the bar (bottom-25)

Common mistakes

  • Hiding columns or whole features on mobile instead of transforming the UI
  • Separate mobile-only API calls that drift from desktop data
  • Showing FAB on desktop (or leaving dense table actions only on mobile with no FAB)
  • Ignoring bottom nav overlap — FAB covered by the bar
  • Custom breakpoints that disagree with SCREENS.md elsewhere in the plugin