8.4 KiB
Mobile-Responsive Implementation Guide
Overview
This document describes the mobile-responsive updates implemented for the CPAS Tracker application. The design targets standard phones (375px+ width) with graceful degradation for smaller devices.
Key Changes
1. Responsive Utility Stylesheet (client/src/styles/mobile.css)
A centralized CSS file providing:
- Media query breakpoints (768px, 480px)
- Touch-friendly tap targets (min 44px height)
- iOS input zoom prevention (16px font size)
- Utility classes for mobile layouts
- Card-based layout helpers
- Horizontal scroll containers
Utility Classes:
.hide-mobile- Hide on screens ≤768px.hide-tablet- Hide on screens ≤1024px.mobile-full-width- Full width on mobile.mobile-stack- Stack flex items vertically.mobile-scroll-x- Enable horizontal scrolling.mobile-card- Card layout container.mobile-sticky-top- Sticky header positioning
2. App Navigation (client/src/App.jsx)
Desktop Behavior:
- Horizontal navigation bar
- Logo left, tabs center, docs button right
- Full tab labels displayed
Mobile Behavior (768px):
- Logo centered with full width
- Tabs stacked horizontally below logo
- Docs button positioned absolutely top-right
- Shortened tab labels ("📊 Dashboard" → "📊")
- Flexible padding (40px → 16px)
Features:
useMediaQuery()hook for responsive detection- Dynamic style injection via
<style>tag - Separate mobile CSS classes for targeted overrides
3. Dashboard Layout (client/src/components/Dashboard.jsx)
Desktop View:
- Traditional HTML table layout
- 7 columns (Index, Employee, Dept, Supervisor, Tier, Points, Violations)
- Horizontal scrolling for overflow
Mobile View (768px):
- Switches to card-based layout (DashboardMobile component)
- Each employee = one card with vertical data rows
- Touch-optimized tap targets
- Improved readability with larger fonts
Mobile Stat Cards:
- 2 columns on phones (480px+)
- 1 column on small phones (<480px)
- Reduced font sizes (28px → 24px)
- Compact padding
Toolbar Adjustments:
- Search input: 260px → 100% width
- Buttons stack vertically
- Full-width button styling
4. Mobile Dashboard Component (client/src/components/DashboardMobile.jsx)
A dedicated mobile-optimized employee card component:
Card Structure:
+--------------------------------+
| Employee Name [Button] |
| [At Risk Badge if applicable] |
|--------------------------------|
| Tier / Standing: [Badge] |
| Active Points: [Large #] |
| 90-Day Violations: [#] |
| Department: [Name] |
| Supervisor: [Name] |
+--------------------------------+
Visual Features:
- At-risk employees: Gold border + dark gold background
- Touch-friendly employee name buttons
- Color-coded point displays matching tier colors
- Compact spacing (12px margins)
- Subtle shadows for depth
5. Responsive Breakpoints
| Breakpoint | Target Devices | Layout Changes |
|---|---|---|
| 1024px | Tablets & below | Reduced padding, simplified nav |
| 768px | Phones (landscape) | Card layouts, stacked navigation |
| 480px | Small phones | Single-column stats, minimal spacing |
| 375px | iPhone SE/6/7/8 | Optimized for minimum supported width |
6. Touch Optimization
Tap Target Sizes:
- All buttons: 44px minimum height (iOS/Android guidelines)
- Form inputs: 44px minimum height
- Navigation tabs: 44px touch area
Typography:
- Form inputs: 16px font size (prevents iOS zoom-in on focus)
- Readable body text: 13-14px
- Headers scale down appropriately
Scrolling:
-webkit-overflow-scrolling: touchfor smooth momentum scrolling- Horizontal scroll on tables (desktop fallback)
- Vertical card scrolling on mobile
Implementation Details
Media Query Hook
function useMediaQuery(query) {
const [matches, setMatches] = useState(false);
useEffect(() => {
const media = window.matchMedia(query);
if (media.matches !== matches) setMatches(media.matches);
const listener = () => setMatches(media.matches);
media.addEventListener('change', listener);
return () => media.removeEventListener('change', listener);
}, [matches, query]);
return matches;
}
Usage:
const isMobile = useMediaQuery('(max-width: 768px)');
Conditional Rendering Pattern
{isMobile ? (
<DashboardMobile employees={filtered} onEmployeeClick={setSelectedId} />
) : (
<table style={s.table}>
{/* Desktop table layout */}
</table>
)}
Dynamic Style Injection
const mobileStyles = `
@media (max-width: 768px) {
.dashboard-wrap {
padding: 16px !important;
}
}
`;
return (
<>
<style>{mobileStyles}</style>
{/* Component JSX */}
</>
);
Testing Checklist
Desktop (>768px)
- Navigation displays horizontally
- Dashboard shows full table
- All columns visible
- Docs button on right side
- Full tab labels visible
Tablet (768px - 1024px)
- Reduced padding maintains readability
- Stats cards wrap to 2-3 columns
- Table scrolls horizontally if needed
Mobile Portrait (375px - 768px)
- Logo centered, tabs stacked
- Dashboard shows card layout
- Search input full width
- Buttons stack vertically
- Employee cards display all data
- Tap targets ≥44px
- No horizontal scroll required
Small Mobile (<480px)
- Stat cards single column
- Text remains readable
- No layout breakage
- Footer wraps properly
iOS-Specific
- Input focus doesn't zoom page (16px font)
- Smooth momentum scrolling
- Tap highlights work correctly
Android-Specific
- Touch feedback visible
- Back button behavior correct
- Keyboard doesn't break layout
Browser Support
- Chrome/Edge: 88+
- Firefox: 85+
- Safari: 14+
- iOS Safari: 14+
- Chrome Android: 88+
Performance Considerations
- Media query hook re-renders only on breakpoint changes, not continuous resize
- Card layout renders fewer DOM elements than table on mobile
- CSS injection happens once per component mount
- No external CSS libraries (zero KB bundle increase)
Future Enhancements
Phase 2 (Optional)
- ViolationForm mobile optimization with multi-step wizard
- Modal responsive sizing and animations
- Swipe gestures for employee cards
- Pull-to-refresh on mobile
- Offline support with service workers
Phase 3 (Advanced)
- Progressive Web App (PWA) capabilities
- Native app shell with Capacitor
- Biometric authentication
- Push notifications
File Structure
client/src/
├── App.jsx # Updated with mobile nav
├── components/
│ ├── Dashboard.jsx # Responsive table/card switch
│ ├── DashboardMobile.jsx # Mobile card layout (NEW)
│ └── ... # Other components
└── styles/
└── mobile.css # Responsive utilities (NEW)
Maintenance Notes
Adding New Components
When creating new components, follow this pattern:
-
Import mobile.css utility classes:
import '../styles/mobile.css'; -
Use media query hook:
const isMobile = useMediaQuery('(max-width: 768px)'); -
Provide mobile-specific styles:
const mobileStyles = ` @media (max-width: 768px) { .my-component { /* mobile overrides */ } } `; -
Test on real devices (Chrome DevTools is insufficient for touch testing)
Debugging Tips
- Use Chrome DevTools Device Mode (Ctrl+Shift+M)
- Test on actual devices when possible
- Check console for media query match state
- Verify tap target sizes with Chrome Lighthouse audit
- Test keyboard behavior on Android
Deployment
- Merge
feature/mobile-responsiveintomaster - Rebuild client bundle:
cd client && npm run build - Restart server
- Clear browser cache (Ctrl+Shift+R)
- Test on production URL with mobile devices
Support
For issues or questions about mobile-responsive implementation:
- Check browser console for errors
- Verify
mobile.cssis loaded - Test with different screen sizes
- Review media query breakpoints
Branch: feature/mobile-responsive
Target Width: 375px+ (standard phones)
Last Updated: March 8, 2026
Maintainer: Jason Stedwell