Modal Component
Fully accessible modal dialog with keyboard navigation, focus management, and animation support
Live Demo
Documentation
# Modal Component
A fully accessible modal dialog component with multiple variants, keyboard navigation, focus management, and animation support. Built with vanilla JavaScript and modern CSS.
Features
- Multiple Variants: Basic, form, confirmation, fullscreen, scrollable
- Accessibility: ARIA attributes, focus trap, screen reader support
- Keyboard Navigation: Escape to close, Tab cycling within modal
- Focus Management: Auto-focus first element, restore focus on close
- Animation: Smooth open/close transitions
- Backdrop: Click-to-close with blur effect
- Programmatic API: Create modals dynamically
- Form Support: Unsaved changes warning
- Responsive: Mobile-optimized fullscreen on small screens
Usage Examples
Basic Modal
Programmatic Modal
// Create alert
modalComponent.alert('Operation completed successfully!', 'Success');// Confirm dialog
const confirmed = await modalComponent.confirm('Delete this item?');
if (confirmed) {
// Perform deletion
}
// Prompt for input
const name = await modalComponent.prompt('Enter your name:', 'Welcome');
Custom Modal Creation
const modal = modalComponent.createModal({
title: 'Custom Modal',
content: 'Custom content here
',
size: 'wide',
buttons: [
{ text: 'Cancel', variant: 'secondary', action: 'dismiss' },
{ text: 'Save', variant: 'primary', id: 'save-btn' }
]
});modalComponent.openModal(modal.id);
Event Handling
// Listen for modal events
document.addEventListener('modal:opened', (e) => {
console.log('Modal opened:', e.detail.modalId);
});document.addEventListener('modal:closed', (e) => {
console.log('Modal closed:', e.detail.modalId);
});
// Trigger via events
document.dispatchEvent(new CustomEvent('modal:open', {
detail: { modalId: 'modal-basic' }
}));
Modal Types
Basic Modal
Standard modal with header, body, and footer sections.
Form Modal
Modal containing form elements with validation support.
Confirmation Modal
Alert-style modal for confirming actions with danger styling.
Fullscreen Modal
Takes up entire viewport, ideal for complex content.
Scrollable Modal
Fixed header/footer with scrollable body content.
API Methods
| Method | Description | Parameters | Returns | |
|---|---|---|---|---|
openModal(id, options) | Open modal by ID | id: string, options: object | void | |
closeModal(id, options) | Close modal | id: string, options: object | void | |
toggleModal(id) | Toggle modal state | id: string | void | |
createModal(options) | Create modal dynamically | options: object | HTMLElement | |
alert(message, title) | Show alert modal | message: string, title: string | HTMLElement | |
confirm(message, title) | Show confirmation | message: string, title: string | Promise | |
prompt(message, title, default) | Show input prompt | message: string, title: string, default: string | Promise |
Events
| Event | Description | Detail |
|---|---|---|
modal:opened | Fired when modal opens | { modalId, modal } |
modal:closed | Fired when modal closes | { modalId, modal } |
modal:open | Trigger modal open | { modalId, options } |
modal:close | Trigger modal close | { modalId, options } |
modal:toggle | Toggle modal state | { modalId } |
Accessibility Notes
- Role & ARIA: Proper
role="dialog"witharia-labelledbyandaria-describedby - Focus Management: Automatic focus trap within modal, restores focus on close
- Keyboard Navigation:
Escape - Close modal-
Tab - Cycle through focusable elements-
Shift+Tab - Reverse cycle
- Screen Reader: Announces modal opening/closing with proper context
- Backdrop: Semi-transparent with blur for visual separation
- Alert Dialogs: Uses
role="alertdialog"for critical confirmations - Form Labels: All form inputs have associated labels
CSS Variables
/ Customize modal appearance /
--modal-bg: white;
--modal-backdrop: rgba(0, 0, 0, 0.5);
--modal-border-radius: 0.75rem;
--modal-shadow: 0 20px 25px rgba(0, 0, 0, 0.15);
--modal-max-width: 32rem;
--modal-z-index: 9999;
Best Practices
1. Always provide meaningful titles and descriptions
2. Use appropriate modal size for content
3. Avoid nested modals
4. Provide clear action buttons
5. Handle unsaved form data before closing
6. Use confirmation modals for destructive actions
7. Ensure content is scrollable if needed
8. Test keyboard navigation thoroughly
Component Code
<!-- Modal Component HTML -->
<div class="modal-showcase">
<!-- Trigger Buttons -->
<button class="modal-trigger" data-modal="modal-basic" aria-label="Open basic modal">
Open Basic Modal
</button>
<button class="modal-trigger" data-modal="modal-form" aria-label="Open form modal">
Open Form Modal
</button>
<button class="modal-trigger" data-modal="modal-confirm" aria-label="Open confirmation modal">
Open Confirmation Modal
</button>
<button class="modal-trigger" data-modal="modal-fullscreen" aria-label="Open fullscreen modal">
Open Fullscreen Modal
</button>
<button class="modal-trigger" data-modal="modal-scrollable" aria-label="Open scrollable modal">
Open Scrollable Modal
</button>
<!-- Basic Modal -->
<div id="modal-basic" class="modal" role="dialog" aria-labelledby="modal-basic-title" aria-describedby="modal-basic-desc" aria-hidden="true">
<div class="modal-backdrop"></div>
<div class="modal-container">
<div class="modal-content">
<header class="modal-header">
<h2 id="modal-basic-title" class="modal-title">Basic Modal</h2>
<button class="modal-close" aria-label="Close modal">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
</header>
<div class="modal-body" id="modal-basic-desc">
<p>This is a basic modal with header, body, and footer sections. It can be closed by clicking the X button, pressing Escape, or clicking outside the modal.</p>
</div>
<footer class="modal-footer">
<button class="modal-button modal-button-secondary" data-modal-dismiss>Cancel</button>
<button class="modal-button modal-button-primary">Confirm</button>
</footer>
</div>
</div>
</div>
<!-- Form Modal -->
<div id="modal-form" class="modal" role="dialog" aria-labelledby="modal-form-title" aria-hidden="true">
<div class="modal-backdrop"></div>
<div class="modal-container">
<div class="modal-content modal-content-wide">
<header class="modal-header">
<h2 id="modal-form-title" class="modal-title">Contact Form</h2>
<button class="modal-close" aria-label="Close modal">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
</header>
<div class="modal-body">
<form class="modal-form">
<div class="form-group">
<label for="name" class="form-label">Name</label>
<input type="text" id="name" class="form-input" required aria-required="true">
</div>
<div class="form-group">
<label for="email" class="form-label">Email</label>
<input type="email" id="email" class="form-input" required aria-required="true">
</div>
<div class="form-group">
<label for="message" class="form-label">Message</label>
<textarea id="message" class="form-textarea" rows="4" required aria-required="true"></textarea>
</div>
</form>
</div>
<footer class="modal-footer">
<button class="modal-button modal-button-secondary" data-modal-dismiss>Cancel</button>
<button class="modal-button modal-button-primary" type="submit">Submit</button>
</footer>
</div>
</div>
</div>
<!-- Confirmation Modal -->
<div id="modal-confirm" class="modal modal-small" role="alertdialog" aria-labelledby="modal-confirm-title" aria-describedby="modal-confirm-desc" aria-hidden="true">
<div class="modal-backdrop"></div>
<div class="modal-container">
<div class="modal-content">
<header class="modal-header modal-header-danger">
<div class="modal-icon modal-icon-danger">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<line x1="12" y1="8" x2="12" y2="12"/>
<line x1="12" y1="16" x2="12.01" y2="16"/>
</svg>
</div>
<h2 id="modal-confirm-title" class="modal-title">Confirm Action</h2>
</header>
<div class="modal-body" id="modal-confirm-desc">
<p>Are you sure you want to delete this item? This action cannot be undone.</p>
</div>
<footer class="modal-footer modal-footer-center">
<button class="modal-button modal-button-secondary" data-modal-dismiss>Cancel</button>
<button class="modal-button modal-button-danger">Delete</button>
</footer>
</div>
</div>
</div>
<!-- Fullscreen Modal -->
<div id="modal-fullscreen" class="modal modal-fullscreen" role="dialog" aria-labelledby="modal-fullscreen-title" aria-hidden="true">
<div class="modal-backdrop"></div>
<div class="modal-container">
<div class="modal-content">
<header class="modal-header">
<h2 id="modal-fullscreen-title" class="modal-title">Fullscreen Modal</h2>
<button class="modal-close" aria-label="Close modal">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
</header>
<div class="modal-body">
<p>This modal takes up the full screen, perfect for complex forms, media viewers, or detailed content that requires maximum space.</p>
<p>The content area is scrollable if needed, and the modal can still be closed using the usual methods.</p>
</div>
<footer class="modal-footer">
<button class="modal-button modal-button-primary" data-modal-dismiss>Close</button>
</footer>
</div>
</div>
</div>
<!-- Scrollable Modal -->
<div id="modal-scrollable" class="modal" role="dialog" aria-labelledby="modal-scrollable-title" aria-hidden="true">
<div class="modal-backdrop"></div>
<div class="modal-container">
<div class="modal-content">
<header class="modal-header modal-header-sticky">
<h2 id="modal-scrollable-title" class="modal-title">Terms and Conditions</h2>
<button class="modal-close" aria-label="Close modal">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
</header>
<div class="modal-body modal-body-scrollable">
<h3>1. Introduction</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<h3>2. Terms of Use</h3>
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<h3>3. Privacy Policy</h3>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
<h3>4. User Responsibilities</h3>
<p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<h3>5. Disclaimers</h3>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.</p>
<h3>6. Contact Information</h3>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum.</p>
</div>
<footer class="modal-footer modal-footer-sticky">
<button class="modal-button modal-button-secondary" data-modal-dismiss>Decline</button>
<button class="modal-button modal-button-primary">Accept</button>
</footer>
</div>
</div>
</div>
</div>Properties & Features
Tags
Features
- Multiple Variants
- Accessibility
- Keyboard Navigation
- Focus Management
- Animation
- Backdrop
- Programmatic API
- Form Support
- Responsive
Browser Support
Last Updated
2025-10-30
Usage Tips
Installation
Copy the HTML, CSS, and JavaScript code above into your project files.
Customization
Modify CSS variables and classes to match your design system.
Accessibility
Ensure all interactive elements have proper ARIA labels and keyboard support.
Responsive Design
Test the component across different screen sizes and devices.