Responsive Layout Patterns
Responsive Layout Patterns
Sanctions Monitor is built mobile-first using Tailwind CSS breakpoints. This page documents the established responsive patterns that all dashboard pages follow, introduced and codified in v0.1.33 (MOB-24).
Breakpoint Reference
| Prefix | Min-width | Typical use |
|---|---|---|
| (none) | 0px | Mobile default |
sm: | 640px | Small tablets, landscape phones |
md: | 768px | Tablets |
lg: | 1024px | Laptops and desktops |
Established Patterns
Filter pill rows
All rows of filter toggle buttons or select controls must use flex-wrap so pills flow onto a second line rather than overflowing the viewport.
<!-- Filter pill row -->
<div class="flex flex-wrap items-center gap-3">
<FilterIcon class="size-4 shrink-0 text-muted-foreground" />
<div class="flex flex-wrap gap-1.5">
<!-- pill buttons -->
</div>
</div>
Data tables
Every data table must be wrapped in an overflow-x-auto container and have a min-w guard on the <table> element. The min-w value should be set so that all essential columns remain readable before horizontal scroll engages.
<!-- Table wrapper -->
<div class="overflow-x-auto rounded-xl border border-border">
<table class="w-full min-w-[540px]">
<!-- ... -->
</table>
</div>
Reference minimum widths used across dashboard pages:
| Page | min-w value |
|---|---|
people/page.tsx | 540px |
sanctions/page.tsx | 560px |
docs/page.tsx | 480px |
Stat/summary grids
All multi-stat summary card grids use a 1 → 2 → 4 column progression:
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<!-- stat cards -->
</div>
Multi-action rows (forms and headers)
Any row that contains both an input (or label) and action buttons should stack vertically on mobile and switch to a horizontal row on sm+:
<div class="flex flex-col gap-3 sm:flex-row sm:items-center">
<input ... />
<button ...>Submit</button>
</div>
Text containers next to action buttons
Whenever a text block sits in a flex row alongside an action button, the text container must have min-w-0 applied. Without it, long strings (API key names, entity names) will push the button off-screen.
<div class="flex items-center justify-between gap-3 rounded-lg border p-3">
<!-- min-w-0 is required here -->
<div class="min-w-0 space-y-0.5">
<p class="truncate text-sm font-medium">Long key name or entity name...</p>
</div>
<button class="shrink-0">Revoke</button>
</div>
Adaptive button labels
For space-constrained headers on mobile, use visually-hidden spans to show a shorter label on mobile and the full label on larger screens:
<button>
<PlusIcon class="size-4" />
<span class="hidden sm:inline">Add New</span>
<span class="sm:hidden" aria-label="Add new item">Add</span>
</button>
Icons in flex rows
All decorative icons placed inside wrapping flex containers should include shrink-0 to prevent them from being squashed when sibling content is long:
<CalendarIcon class="size-4 shrink-0 text-muted-foreground" />
Pages Audit Status
All dashboard sub-pages were audited against these patterns in v0.1.33.
| Page | Status |
|---|---|
billing/page.tsx | ✅ Compliant |
sanctions/page.tsx | ✅ Compliant |
docs/page.tsx | ✅ Compliant |
adverse-media/page.tsx | ✅ Compliant |
matches/page.tsx | ✅ Compliant |
sanctions/changes/page.tsx | ✅ Fixed in v0.1.33 |
settings/page.tsx | ✅ Fixed in v0.1.33 |
people/page.tsx | ✅ Fixed in v0.1.33 |
New Pages Checklist
When building a new dashboard page, verify each of the following before merging:
- Filter pill rows use
flex flex-wrap - All
<table>elements have anoverflow-x-autowrapper and amin-w-[Npx]class - Stat grids use
grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 - Form rows use
flex-col gap-N sm:flex-row - Text containers next to buttons have
min-w-0 - Icons inside flex rows have
shrink-0 - Long text strings inside flex rows use
truncate