7.4 KiB
Executable File
Comprehensive Modal Z-Index Fix Plan
Date: 2026-02-04 Issue: Widespread modal overlay z-index pattern breaking dropdown interactions Scope: 11 modal components across the application Fix Strategy: Unified 3-layer modal restructuring
Executive Summary
Multiple modal components throughout the application use the same problematic pattern:
<div className="fixed inset-0 bg-black/50 ... z-50">
{/* Form with dropdowns inside */}
</div>
This pattern creates a z-index stacking context that blocks native HTML <select> dropdown menus from rendering properly, making them unclickable.
Affected Components by Priority
P0 - CRITICAL: Modals with SELECT Dropdowns (Completely Broken)
| Component | File | Line | Dropdowns | Impact |
|---|---|---|---|---|
| ProxyHostForm | frontend/src/components/ProxyHostForm.tsx |
514 | ACL selector, Security Headers | CRITICAL: Users cannot assign security policies |
| EditMonitorModal | frontend/src/pages/Uptime.tsx |
230 | Monitor type (HTTP/TCP) | HIGH: Users cannot edit monitor configuration |
| CreateMonitorModal | frontend/src/pages/Uptime.tsx |
339 | Monitor type (HTTP/TCP) | HIGH: Users cannot create new monitors |
| InviteUserModal | frontend/src/pages/UsersPage.tsx |
171 | Role, Permission mode | HIGH: Admin cannot invite users with roles |
| EditPermissionsModal | frontend/src/pages/UsersPage.tsx |
434 | Permission mode, Allowed/Blocked hosts | HIGH: Admin cannot modify user permissions |
| BanIPModal | frontend/src/pages/CrowdSecConfig.tsx |
1175 | Ban duration | MEDIUM: Admin cannot set custom ban durations |
| RemoteServerForm | frontend/src/components/RemoteServerForm.tsx |
69 | Provider (Generic/Docker/K8s) | MEDIUM: Users cannot add remote servers |
P1 - HIGH: Modals with Other Interactive Elements
| Component | File | Line | Elements | Impact |
|---|---|---|---|---|
| PasswordPromptModal | frontend/src/pages/Account.tsx |
473 | Password input, buttons | LOW: Simple inputs work |
| EmailConfirmModal | frontend/src/pages/Account.tsx |
523 | Buttons only | NONE: No form inputs |
P2 - MEDIUM: Modal Pattern Analysis Required
| Component | File | Line | Status | Impact |
|---|---|---|---|---|
| ConfirmDialog | frontend/src/pages/WafConfig.tsx |
72 | Buttons only | NONE: No form inputs |
| SecurityNotificationModal | frontend/src/components/SecurityNotificationSettingsModal.tsx |
58 | TBD - Need analysis | UNKNOWN |
| ImportSitesModal | frontend/src/components/ImportSitesModal.tsx |
75 | TBD - Need analysis | UNKNOWN |
| CertificateCleanupDialog | frontend/src/components/dialogs/CertificateCleanupDialog.tsx |
27 | Buttons only | NONE: No form inputs |
| ImportSuccessModal | frontend/src/components/dialogs/ImportSuccessModal.tsx |
30 | Display only | NONE: No form inputs |
Unified Fix Strategy
Solution: 3-Layer Modal Architecture
Replace the problematic single-layer pattern:
// ❌ BROKEN: Single layer blocks dropdown menus
<div className="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50">
<form>
<select> {/* BROKEN: Can't click */} </select>
</form>
</div>
With the 3-layer pattern:
// ✅ FIXED: Separate layers for proper z-index stacking
<>
{/* Layer 1: Background overlay (z-40) */}
<div className="fixed inset-0 bg-black/50 z-40" onClick={onCancel} />
{/* Layer 2: Form container (z-50, pointer-events-none) */}
<div className="fixed inset-0 flex items-center justify-center p-4 pointer-events-none z-50">
{/* Layer 3: Form content (pointer-events-auto) */}
<div className="... pointer-events-auto">
<form className="pointer-events-auto">
<select> {/* WORKS: Dropdown renders above all layers */} </select>
</form>
</div>
</div>
</>
Implementation Plan
Phase 1: P0 Critical Components (4-6 hours)
Priority Order (most business-critical first):
- ProxyHostForm.tsx (30 min) - Security policy assignment
- UsersPage.tsx - InviteUserModal (20 min) - User management
- UsersPage.tsx - EditPermissionsModal (30 min) - Permission management
- Uptime.tsx - Both modals (45 min) - Monitor management
- RemoteServerForm.tsx (20 min) - Infrastructure management
- CrowdSecConfig.tsx - BanIPModal (20 min) - Security management
Phase 2: P1 Components (1-2 hours)
Analysis and fix of remaining interactive modals if needed.
Phase 3: Testing & Validation (2-3 hours)
- Manual testing of all dropdown interactions
- E2E test updates
- Cross-browser verification
Total Estimated Time: 7-11 hours
Testing Strategy
Manual Testing Checklist
For each P0 component:
- Modal opens correctly
- Background overlay click-to-close works
- All dropdown menus open and respond to clicks
- Dropdown options are selectable
- Form submission works with selected values
- ESC key closes modal
- Tab navigation works through form elements
Automated Testing
E2E Tests to Update:
tests/integration/proxy-acl-integration.spec.ts- ProxyHostForm dropdownstests/security/user-management.spec.ts- UsersPage modalstests/uptime/*.spec.ts- Uptime monitor modals- Any tests interacting with the affected modals
Unit Tests:
- Modal rendering tests should continue to pass
- Form submission tests should continue to pass
Risk Assessment
Risk Level: LOW-MEDIUM
Mitigating Factors: ✅ Non-breaking change (only CSS/DOM structure) ✅ Identical fix pattern across all components ✅ Well-understood solution (already documented in ConfigReloadOverlay) ✅ Only affects modal presentation layer
Risk Areas: ⚠️ Multiple files being modified simultaneously ⚠️ Modal close behavior could be affected ⚠️ CSS specificity or responsive behavior could change
Mitigation Strategy:
- Fix components one at a time
- Test each component thoroughly before moving to next
- Keep changes minimal and focused
- Maintain existing CSS classes and styling
Success Criteria
- All P0 modal dropdowns are clickable and functional
- Modal open/close behavior unchanged
- Background overlay click-to-close still works
- ESC key behavior unchanged
- All existing E2E tests pass
- No new console errors or warnings
- Cross-browser compatibility maintained (Chrome, Firefox, Safari, Edge)
Implementation Notes
CSS Classes to Add:
pointer-events-noneon form container layerspointer-events-autoon form content elements
CSS Classes to Modify:
- Change overlay z-index from
z-50toz-40 - Keep form container at
z-50
Accessibility:
- Maintain
role="dialog"andaria-modal="true"attributes - Ensure Tab navigation still works correctly
- Preserve ESC key handling
Post-Implementation Actions
- Documentation Update: Update modal component patterns in design system docs
- Code Review Guidelines: Add z-index modal pattern to code review checklist
- Linting Rule: Consider ESLint rule to detect problematic modal patterns
- Design System: Create reusable Modal component with correct z-index pattern
This comprehensive fix addresses the root cause across the entire application, preventing future occurrences of the same issue.