A production-ready, accessible modal system for React applications. This demonstrates centralized modal management, accessibility, and clean architecture, without any UI library.
-
Centralized modal registry using a ModalProvider
-
Type-safe modals with discriminated unions
-
Portal-based rendering (
createPortal) for proper stacking -
Keyboard accessibility:
- ESC to close
- Focus trap
- Focus restoration
-
Backdrop overlay and minimal styling
-
Clean API for opening modals anywhere in the app
-
Scalable architecture (multiple modal types, reusable logic)
-
Separation of modal content and modal management logic
This example is ideal for demonstrating senior frontend engineering skills, especially for accessibility-aware design.
- Wrap your app with
<ModalProvider> - Use
useModal()to open any modal by type:
const { openModal, closeModal } = useModal();
openModal('confirm', {
message: 'Are you sure?',
onConfirm: () => alert('Confirmed!'),
});<ModalRoot />handles rendering the correct modal, overlay, and focus management.
- Avoids scattered modal logic across components
- Centralized focus, keyboard, and accessibility handling
- Easy to maintain and extend for multiple modals
- Supports proper screen reader and keyboard UX
- Clean separation of concerns for real-world applications
{
isOpen && <Modal />;
}Problems:
- Focus not managed
- No keyboard accessibility
- No centralized modal control
- Hard to scale or extend
- Centralized provider for all modals
- Portal rendering ensures correct stacking
- Focus trap + ESC handling
- Type-safe modal payloads
- Reusable modal API
src/
modal/
ModalProvider.tsx
useModal.ts
ModalRoot.tsx
FocusTrap.tsx
types.ts
modals/
ConfirmModal.tsx
InfoModal.tsx
styles/
modal.css
App.tsx
- React
- TypeScript
- Vite
- Plain CSS (minimal styling)
No external modal libraries — everything is implemented explicitly to demonstrate understanding.
npm install
npm run dev- FocusTrap handles tabbing and focus restoration
- ModalRoot handles portal rendering and ESC key closing
- Styles are minimal; feel free to adapt to your design system
- Additional modal types can be added by extending
ModalTypeandModalPayloadMap
MIT