Files
cpas/MOBILE_RESPONSIVE.md

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: touch for 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

  1. Media query hook re-renders only on breakpoint changes, not continuous resize
  2. Card layout renders fewer DOM elements than table on mobile
  3. CSS injection happens once per component mount
  4. 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:

  1. Import mobile.css utility classes:

    import '../styles/mobile.css';
    
  2. Use media query hook:

    const isMobile = useMediaQuery('(max-width: 768px)');
    
  3. Provide mobile-specific styles:

    const mobileStyles = `
      @media (max-width: 768px) {
        .my-component { /* mobile overrides */ }
      }
    `;
    
  4. 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

  1. Merge feature/mobile-responsive into master
  2. Rebuild client bundle: cd client && npm run build
  3. Restart server
  4. Clear browser cache (Ctrl+Shift+R)
  5. Test on production URL with mobile devices

Support

For issues or questions about mobile-responsive implementation:

  • Check browser console for errors
  • Verify mobile.css is 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