alertdialog
A type of dialog that contains an alert message, where initial focus goes to an element within the dialog. Used for important, time-sensitive information that requires user acknowledgment or action.
Overview
The alertdialog role is used for modal dialogs that interrupt the user's workflow to communicate an important message and require a response. Unlike a standard dialog, an alertdialog conveys urgency and importance.
Alert dialogs are appropriate for error messages, confirmation prompts for destructive actions (like deleting data), or critical system notifications that require immediate attention.
When to Use Alert Dialog
- • Confirming destructive actions (delete, remove, etc.)
- • Displaying critical error messages
- • Warning users about potential data loss
- • Requiring acknowledgment of important information
Live Demo
Click the button to see an accessible alert dialog in action
Alert Dialog vs Dialog
alertdialog
- •Used for urgent, important messages
- •Requires immediate user response
- •Focus goes to an action button
- •Always modal (blocks background)
- •Screen readers announce with urgency
dialog
- •Used for general interactions
- •User can take time to interact
- •Focus goes to first focusable element
- •Can be modal or non-modal
- •Screen readers announce normally
Required Attributes
aria-labelledbyoraria-labelEvery alert dialog must have an accessible name. Use aria-labelledby to reference the alert title, or aria-label to provide a direct label.
aria-describedby(strongly recommended)Should reference the element containing the alert message. This ensures screen readers announce the full context of the alert.
Supported Attributes
aria-modalShould be set to "true" for alert dialogs (always modal)
aria-describedbyReferences element(s) describing the alert message
aria-labelledbyReferences the element that labels the alert (usually the title)
aria-labelProvides a string label for the alert dialog
Code Examples
Basic Alert Dialog
<!-- Basic Alert Dialog Example -->
<div role="alertdialog"
aria-labelledby="alert-title"
aria-describedby="alert-desc"
aria-modal="true">
<h2 id="alert-title">Confirm Deletion</h2>
<p id="alert-desc">
Warning: This will permanently delete all your data.
This action cannot be undone.
</p>
<div>
<button autofocus>Cancel</button>
<button>Delete Permanently</button>
</div>
</div>Error Alert Dialog
<!-- Error Alert Dialog -->
<div role="alertdialog"
aria-labelledby="error-title"
aria-describedby="error-message"
aria-modal="true">
<div class="error-icon" aria-hidden="true">⚠️</div>
<h2 id="error-title">Connection Error</h2>
<p id="error-message">
Unable to connect to the server. Please check your
internet connection and try again.
</p>
<button autofocus>Retry</button>
<button>Cancel</button>
</div>Confirmation Alert Dialog
<!-- Confirmation Alert Dialog -->
<div role="alertdialog"
aria-labelledby="confirm-title"
aria-modal="true">
<h2 id="confirm-title">Discard Changes?</h2>
<p>
You have unsaved changes. Are you sure you want to
leave this page? Your changes will be lost.
</p>
<div class="button-group">
<button autofocus>Stay on Page</button>
<button class="danger">Discard Changes</button>
</div>
</div>JavaScript Implementation
// JavaScript Alert Dialog Implementation
function showAlertDialog(options) {
const { title, message, confirmText = 'OK', cancelText = 'Cancel' } = options;
// Create dialog
const dialog = document.createElement('div');
dialog.setAttribute('role', 'alertdialog');
dialog.setAttribute('aria-modal', 'true');
dialog.setAttribute('aria-labelledby', 'alert-title');
dialog.setAttribute('aria-describedby', 'alert-desc');
// Store previously focused element
const previouslyFocused = document.activeElement;
// Build dialog HTML
dialog.innerHTML = `
<div class="alert-dialog-content">
<h2 id="alert-title">${title}</h2>
<p id="alert-desc">${message}</p>
<div class="button-group">
<button class="cancel-btn">${cancelText}</button>
<button class="confirm-btn" autofocus>${confirmText}</button>
</div>
</div>
`;
// Create backdrop
const backdrop = document.createElement('div');
backdrop.className = 'alert-dialog-backdrop';
backdrop.appendChild(dialog);
document.body.appendChild(backdrop);
// Prevent body scroll
document.body.style.overflow = 'hidden';
// Focus the confirm button (or first button with autofocus)
setTimeout(() => {
const autofocusBtn = dialog.querySelector('[autofocus]');
if (autofocusBtn) {
autofocusBtn.focus();
}
}, 0);
// Handle button clicks
return new Promise((resolve) => {
const cancelBtn = dialog.querySelector('.cancel-btn');
const confirmBtn = dialog.querySelector('.confirm-btn');
const close = (confirmed) => {
backdrop.remove();
document.body.style.overflow = '';
previouslyFocused?.focus();
resolve(confirmed);
};
cancelBtn?.addEventListener('click', () => close(false));
confirmBtn?.addEventListener('click', () => close(true));
// Handle escape key
dialog.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
close(false);
}
});
// Trap focus
const focusableElements = dialog.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
dialog.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstElement) {
e.preventDefault();
lastElement.focus();
} else if (!e.shiftKey && document.activeElement === lastElement) {
e.preventDefault();
firstElement.focus();
}
}
});
});
}
// Usage
const confirmed = await showAlertDialog({
title: 'Delete File',
message: 'Are you sure you want to delete this file? This cannot be undone.',
confirmText: 'Delete',
cancelText: 'Cancel'
});
if (confirmed) {
// User confirmed
deleteFile();
}React Component
// React Alert Dialog Component
import { useEffect, useRef } from 'react';
function AlertDialog({ isOpen, onClose, onConfirm, title, message, confirmText = 'OK', cancelText = 'Cancel' }) {
const dialogRef = useRef(null);
const confirmBtnRef = useRef(null);
const previousFocusRef = useRef(null);
useEffect(() => {
if (isOpen) {
// Store previous focus
previousFocusRef.current = document.activeElement;
// Focus the confirm button
setTimeout(() => {
confirmBtnRef.current?.focus();
}, 0);
// Prevent body scroll
document.body.style.overflow = 'hidden';
} else {
// Restore focus
if (previousFocusRef.current) {
previousFocusRef.current.focus();
}
// Restore body scroll
document.body.style.overflow = '';
}
return () => {
document.body.style.overflow = '';
};
}, [isOpen]);
if (!isOpen) return null;
const handleConfirm = () => {
onConfirm?.();
onClose();
};
return (
<div
className="alert-dialog-backdrop"
onClick={(e) => {
if (e.target === e.currentTarget) {
onClose();
}
}}
>
<div
ref={dialogRef}
role="alertdialog"
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-desc"
aria-modal="true"
onClick={(e) => e.stopPropagation()}
>
<div className="alert-icon" aria-hidden="true">⚠️</div>
<h2 id="alert-dialog-title">{title}</h2>
<p id="alert-dialog-desc">{message}</p>
<div className="button-group">
<button onClick={onClose}>
{cancelText}
</button>
<button
ref={confirmBtnRef}
onClick={handleConfirm}
className="primary"
>
{confirmText}
</button>
</div>
</div>
</div>
);
}
// Usage
function App() {
const [showAlert, setShowAlert] = useState(false);
const handleDelete = () => {
setShowAlert(true);
};
const confirmDelete = () => {
// Perform deletion
console.log('File deleted');
};
return (
<>
<button onClick={handleDelete}>Delete File</button>
<AlertDialog
isOpen={showAlert}
onClose={() => setShowAlert(false)}
onConfirm={confirmDelete}
title="Confirm Deletion"
message="Are you sure you want to delete this file? This action cannot be undone."
confirmText="Delete"
cancelText="Cancel"
/>
</>
);
}Keyboard Support
Moves focus to the next focusable element inside the alert dialog.
Moves focus to the previous focusable element inside the alert dialog.
Closes the alert dialog (typically triggers cancel action).
Activates the focused button (confirm or cancel).
Best Practices
Always use alertdialog for critical messages requiring immediate action
Include both aria-labelledby and aria-describedby for context
Focus should go to the least destructive action (e.g., Cancel button)
Set aria-modal="true" to indicate background is inert
Provide clear, concise alert messages
Use distinct visual styling (warning colors, icons)
Keep the number of actions minimal (typically 2 buttons)
Trap focus within the alert dialog
Don't use alertdialog for non-urgent information
Don't overuse alertdialogs - they interrupt workflow
Don't focus on destructive actions by default
Don't use vague messages like "Are you sure?"
Accessibility Notes
Screen Reader Announcements
When an alert dialog opens, screen readers will announce it with higher priority than a standard dialog. The role, label, and description are announced immediately, alerting the user to the urgency of the message. This is why alertdialog should only be used for truly important messages.
Initial Focus Placement
For alert dialogs, focus should typically go to the least destructive action (usually the Cancel or Close button). This prevents accidental confirmation of destructive actions. Use the autofocus attribute or JavaScript to set initial focus appropriately.
Visual Indicators
Alert dialogs should have distinctive visual styling to convey urgency. Use warning colors (yellow, orange, red), prominent icons (⚠️, ⛔), and clear typography. This benefits all users, not just those using assistive technologies.
Modal Behavior
Alert dialogs are always modal and must block interaction with background content. Use aria-modal="true" and JavaScript to make background content inert. This ensures keyboard and screen reader users cannot accidentally interact with hidden content.