Fix Bootstrap 5 modal aria-hidden focus timing issue

Added event listeners to manage aria-hidden attribute timing during
modal open/close transitions to prevent accessibility warnings.

Changes:
- Listen to hide.bs.modal to remove aria-hidden before closing
- Listen to hidden.bs.modal to restore aria-hidden after fully closed
- Listen to show.bs.modal to remove aria-hidden when opening
- Use setTimeout to ensure focus has moved before setting aria-hidden

This prevents the "Blocked aria-hidden on element with focus" warning
by ensuring aria-hidden is only set after focus has left the modal.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ken Johnson
2025-12-07 01:33:45 -05:00
parent be1994e0c1
commit c5cd2828a5
+23 -3
View File
@@ -132,24 +132,44 @@
<script> <script>
function initCredentialsModal() { function initCredentialsModal() {
const showCredsBtn = document.getElementById('show_creds_btn'); const showCredsBtn = document.getElementById('show_creds_btn');
if (showCredsBtn) { const modalElement = document.getElementById('credentialsModal');
if (showCredsBtn && modalElement) {
// Remove any existing listeners // Remove any existing listeners
const newBtn = showCredsBtn.cloneNode(true); const newBtn = showCredsBtn.cloneNode(true);
showCredsBtn.parentNode.replaceChild(newBtn, showCredsBtn); showCredsBtn.parentNode.replaceChild(newBtn, showCredsBtn);
// Fix aria-hidden timing issue with Bootstrap 5
modalElement.addEventListener('hide.bs.modal', function() {
// Remove aria-hidden before the modal closes to prevent focus conflict
this.removeAttribute('aria-hidden');
});
modalElement.addEventListener('hidden.bs.modal', function() {
// Add aria-hidden back after modal is fully closed and focus has moved
setTimeout(() => {
this.setAttribute('aria-hidden', 'true');
}, 0);
});
modalElement.addEventListener('show.bs.modal', function() {
// Ensure aria-hidden is removed when opening
this.removeAttribute('aria-hidden');
});
newBtn.addEventListener('click', function(event) { newBtn.addEventListener('click', function(event) {
event.preventDefault(); event.preventDefault();
fetch('<%= credentials_tutorials_path %>') fetch('<%= credentials_tutorials_path %>')
.then(response => response.text()) .then(response => response.text())
.then(html => { .then(html => {
document.getElementById('modal_content').innerHTML = html; document.getElementById('modal_content').innerHTML = html;
const modal = new bootstrap.Modal(document.getElementById('credentialsModal')); const modal = new bootstrap.Modal(modalElement);
modal.show(); modal.show();
}) })
.catch(error => { .catch(error => {
console.error('Error loading credentials:', error); console.error('Error loading credentials:', error);
document.getElementById('modal_content').innerHTML = '<p class="text-danger">Error loading credentials. Please try again.</p>'; document.getElementById('modal_content').innerHTML = '<p class="text-danger">Error loading credentials. Please try again.</p>';
const modal = new bootstrap.Modal(document.getElementById('credentialsModal')); const modal = new bootstrap.Modal(modalElement);
modal.show(); modal.show();
}); });
}); });