Mobile-First
Most Mukoko users access the ecosystem on mobile devices, often on mid-range Android phones with variable network quality. Mobile is not an afterthought — it is the primary platform.
Design principles
- Start with mobile — design the smallest screen first, then enhance for larger screens
- Optimize for touch — 48px minimum targets, thumb-friendly action placement
- Minimize data usage — lazy load images, compress assets, avoid unnecessary requests
- Work offline — core features should function without a network connection
- Fast first paint — show skeleton content immediately, load data progressively
Bottom navigation
Use mukoko-bottom-nav for app-level navigation on mobile. This places primary navigation in the thumb zone:
{/* Mobile: bottom nav. Desktop: sidebar */}
<div className="hidden md:block">
<MukokoSidebar />
</div>
<div className="fixed inset-x-0 bottom-0 md:hidden">
<MukokoBottomNav
items={[
{ label: "Home", href: "/", icon: Home },
{ label: "Search", href: "/search", icon: Search },
{ label: "Events", href: "/events", icon: Calendar },
{ label: "Profile", href: "/profile", icon: User },
]}
/>
</div>Limit bottom nav to 4-5 items maximum. More items create touch targets that are too small.
Sheet over dialog
On mobile, use Sheet (slides from the bottom) instead of Dialog (centered modal). Sheets are easier to reach and dismiss:
{/* Responsive: Sheet on mobile, Dialog on desktop */}
<div className="hidden sm:block">
<Dialog>
<DialogTrigger asChild><Button>Open</Button></DialogTrigger>
<DialogContent>{/* Content */}</DialogContent>
</Dialog>
</div>
<div className="sm:hidden">
<Sheet>
<SheetTrigger asChild><Button>Open</Button></SheetTrigger>
<SheetContent side="bottom">{/* Same content */}</SheetContent>
</Sheet>
</div>Touch targets
All interactive elements must be at least 48px in the touch dimension:
{/* Correct — sufficient touch target */}
<button className="flex h-12 items-center gap-3 px-4">
<Icon className="size-5" />
<span>Menu item</span>
</button>
{/* Incorrect — too small for touch */}
<button className="h-6 px-2 text-xs">Tap</button>For lists of tappable items, use the Item component which provides the correct touch target:
<ItemGroup>
<Item>
<ItemContent>
<ItemTitle>Event name</ItemTitle>
<ItemDescription>15 June 2026</ItemDescription>
</ItemContent>
</Item>
</ItemGroup>Progressive loading
Sequential mount
Use the lazy-section pattern to load page sections one at a time, reducing the initial bundle size:
<LazySection id="hero" priority={0}>
<HeroSection />
</LazySection>
<LazySection id="stats" priority={1}>
<StatsSection />
</LazySection>
<LazySection id="chart" priority={2}>
<ChartSection />
</LazySection>Image loading
- Use
loading="lazy"on images below the fold - Provide explicit
widthandheightto prevent layout shift - Use thumbnail/placeholder images for progressive loading
Memory pressure
On low-memory devices, the useMemoryPressure hook detects pressure and can unload offscreen sections:
const { isUnderPressure } = useMemoryPressure()
{isUnderPressure ? (
<Skeleton className="h-64" />
) : (
<ExpensiveChart data={data} />
)}Network awareness
Design for intermittent connectivity:
{/* Offline indicator */}
{!navigator.onLine && (
<Alert variant="warning" className="mx-4 mt-2">
<AlertTitle>You are offline</AlertTitle>
<AlertDescription>
Some features may be limited. Changes will sync when you reconnect.
</AlertDescription>
</Alert>
)}Text input on mobile
- Use appropriate
typeattributes for on-screen keyboard optimization type="email"shows the @ keytype="tel"shows the number padinputMode="numeric"for numeric input without the tel format- Use
autoCompleteto reduce typing
<Input type="email" autoComplete="email" inputMode="email" />
<Input type="tel" autoComplete="tel" />
<Input inputMode="numeric" pattern="[0-9]*" />Responsive patterns summary
| Pattern | Mobile | Desktop |
|---|---|---|
| Navigation | Bottom nav | Sidebar |
| Modals | Bottom sheet | Centered dialog |
| Data tables | Card list | Full table |
| Sidebar | Hidden/overlay | Persistent |
| Stats grid | 2 columns | 4 columns |
| Filter bar | Collapsible | Always visible |
| Images | Full width | Constrained |