Modal
Focused dialog windows that overlay the interface for important interactions, confirmations, and form submissions.
Basic Modal
Standard Dialog
A centered modal with title, content, and action buttons.
<div class="modal-backdrop">
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title">
<header class="modal-header">
<h2 id="modal-title">Modal Title</h2>
<button class="modal-close" aria-label="Close">×</button>
</header>
<div class="modal-body">
<p>Modal content goes here...</p>
</div>
<footer class="modal-footer">
<button class="btn btn-secondary">Cancel</button>
<button class="btn btn-primary">Confirm</button>
</footer>
</div>
</div>
Modal Sizes
Size Variants
Small for confirmations, medium for forms, large for complex content.
.modal-sm { max-width: 320px; } /* Confirmations */
.modal-md { max-width: 480px; } /* Default */
.modal-lg { max-width: 640px; } /* Complex content */
.modal-xl { max-width: 800px; } /* Full forms */
Confirmation Dialog
Destructive Action
Use for irreversible actions with clear warning styling.
<div class="modal modal-sm">
<header class="modal-header">
<h2>Delete this item?</h2>
</header>
<div class="modal-body">
<p>This action cannot be undone. The item will be permanently removed.</p>
</div>
<footer class="modal-footer">
<button class="btn btn-secondary">Cancel</button>
<button class="btn btn-error">Delete</button>
</footer>
</div>
Modal with Form
Form Dialog
Modals containing form inputs for data collection.
<div class="modal modal-md">
<header class="modal-header">
<h2>Add New Item</h2>
<button class="modal-close">×</button>
</header>
<div class="modal-body">
<div class="form-group">
<label>Name</label>
<input type="text" class="input" placeholder="Enter name">
</div>
<div class="form-group">
<label>Description</label>
<textarea class="textarea" rows="3"></textarea>
</div>
</div>
<footer class="modal-footer">
<button class="btn btn-secondary">Cancel</button>
<button class="btn btn-primary">Save</button>
</footer>
</div>
CSS Implementation
/* Backdrop */
.modal-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
backdrop-filter: blur(4px);
display: flex;
align-items: center;
justify-content: center;
padding: var(--space-4);
z-index: var(--z-modal);
animation: backdrop-fade-in var(--duration-normal) var(--ease-ease-out);
}
@keyframes backdrop-fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
/* Modal */
.modal {
background: var(--bg-elevated);
border-radius: var(--radius-xl);
box-shadow: var(--shadow-xl);
width: 100%;
max-width: 480px;
max-height: calc(100vh - var(--space-8));
overflow: hidden;
display: flex;
flex-direction: column;
animation: modal-slide-in var(--duration-slow) var(--ease-spring);
}
@keyframes modal-slide-in {
from {
opacity: 0;
transform: scale(0.95) translateY(10px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
/* Header */
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-5) var(--space-6);
border-bottom: 1px solid var(--border-subtle);
}
.modal-header h2 {
font-family: var(--font-display);
font-size: var(--text-lg);
font-weight: var(--font-weight-semibold);
margin: 0;
}
.modal-close {
width: 32px;
height: 32px;
border: none;
background: transparent;
border-radius: var(--radius-md);
cursor: pointer;
font-size: var(--text-xl);
color: var(--text-muted);
display: flex;
align-items: center;
justify-content: center;
transition: all var(--duration-fast) var(--ease-ease-out);
}
.modal-close:hover {
background: var(--bg-secondary);
color: var(--text-primary);
}
/* Body */
.modal-body {
padding: var(--space-6);
overflow-y: auto;
flex: 1;
}
.modal-body p {
color: var(--text-secondary);
line-height: var(--leading-relaxed);
}
/* Footer */
.modal-footer {
display: flex;
justify-content: flex-end;
gap: var(--space-3);
padding: var(--space-4) var(--space-6);
border-top: 1px solid var(--border-subtle);
background: var(--bg-secondary);
}
/* Sizes */
.modal-sm { max-width: 320px; }
.modal-md { max-width: 480px; }
.modal-lg { max-width: 640px; }
.modal-xl { max-width: 800px; }
/* Glass variant */
.modal-glass {
background: var(--bg-glass);
backdrop-filter: blur(var(--glass-blur-heavy));
border: 1px solid var(--border-glass);
}
Accessibility
Focus Trap
Focus is trapped within the modal. Tab cycles through focusable elements without leaving.
Escape to Close
Pressing Escape dismisses the modal. Click outside (backdrop) also closes it.
ARIA Attributes
Use role="dialog", aria-modal="true", and aria-labelledby for the title.
Focus Restoration
When closed, focus returns to the element that triggered the modal.