(function() {
document.addEventListener('DOMContentLoaded', function() {
// Add lang="en" to if missing (WCAG 3.1.1)
if (!document.documentElement.getAttribute('lang')) {
document.documentElement.setAttribute('lang', 'en');
}
// Add if empty (WCAG 2.4.2)
var titleElement = document.querySelector('title');
if (!titleElement || titleElement.textContent.trim() === '') {
document.title = 'Default Title'; // Set a default title
}
// Add skip navigation link before first focusable element (WCAG 2.4.1)
var firstFocusable = document.querySelector('a, area, button, input, select, textarea, [tabindex]:not([tabindex="-1"])');
if (firstFocusable) {
var skipLink = document.createElement('a');
skipLink.href = '#main'; // Assuming the main content has an ID of "main"
skipLink.textContent = 'Skip to main content';
skipLink.style.position = 'absolute';
skipLink.style.left = '-9999px'; // Hide link visually
document.body.insertBefore(skipLink, firstFocusable);
}
// Add alt="" to decorative images (WCAG 1.1.1)
var decorativeImages = document.querySelectorAll('img:not([alt]):not([role="presentation"]), [role="img"]:not([alt])');
decorativeImages.forEach(function(img) {
img.setAttribute('alt', '');
});
// Add aria-label to icon-only buttons with no text (WCAG 4.1.2)
var iconButtons = document.querySelectorAll('button:not(:empty):not([aria-label]), [role="button"]:not(:empty):not([aria-label])');
iconButtons.forEach(function(btn) {
var ariaLabel = btn.querySelector('span, img') ? btn.querySelector('span, img').alt || btn.querySelector('span, img').getAttribute('aria-label') : 'Icon button';
btn.setAttribute('aria-label', ariaLabel);
});
// Add role="main" to main content area if missing (WCAG 1.3.1)
var mainElement = document.querySelector('main');
if (mainElement && !mainElement.getAttribute('role')) {
mainElement.setAttribute('role', 'main');
}
// Ensure focus is visible (inject CSS for :focus outline if missing) (WCAG 2.4.7)
var style = document.createElement('style');
style.textContent = 'button:focus, a:focus, input:focus { outline: 2px solid blue; }';
document.head.appendChild(style);
// Add aria-required="true" to required form fields (WCAG 3.3.2)
var requiredFields = document.querySelectorAll('input[required], select[required], textarea[required]');
requiredFields.forEach(function(field) {
field.setAttribute('aria-required', 'true');
});
// Add autocomplete attributes to common form fields (name, email, tel) (WCAG 3.3.2)
var autocompleteFields = document.querySelectorAll('input[type="text"], input[type="email"], input[type="tel"]');
autocompleteFields.forEach(function(field) {
if (field.type === 'email') {
field.setAttribute('autocomplete', 'email');
} else if (field.type === 'tel') {
field.setAttribute('autocomplete', 'tel');
} else {
field.setAttribute('autocomplete', 'name');
}
});
// Add aria-hidden="true" to decorative SVGs (WCAG 1.1.1)
var decorativeSVGs = document.querySelectorAll('svg:not([aria-hidden]):not([role="img"])');
decorativeSVGs.forEach(function(svg) {
svg.setAttribute('aria-hidden', 'true');
});
// Ensure all form inputs have associated labels via aria-labelledby or for/id (WCAG 2.5.3)
var formInputs = document.querySelectorAll('input, select, textarea');
formInputs.forEach(function(input) {
var label = document.querySelector('label[for="' + input.id + '"]');
if (label) {
input.setAttribute('aria-labelledby', label.id);
}
});
// Add role="navigation" and aria-label to nav elements (WCAG 1.3.1)
var navElements = document.querySelectorAll('nav:not([role])');
navElements.forEach(function(nav) {
nav.setAttribute('role', 'navigation');
if (!nav.getAttribute('aria-label')) {
nav.setAttribute('aria-label', 'Main navigation'); // Default label
}
});
// Fix empty link text with aria-label (WCAG 2.4.4)
var emptyLinks = document.querySelectorAll('a:not(:empty):not([aria-label])');
emptyLinks.forEach(function(link) {
link.setAttribute('aria-label', 'Link to ' + link.href); // Sets description based on link URL
});
console.log('Accessibility fixes applied:');
console.log('1. lang attribute added to html');
console.log('2. Title added if empty');
console.log('3. Skip navigation link added');
console.log('4. alt="" added to decorative images');
console.log('5. aria-label added to icon-only buttons');
console.log('6. role="main" added to main element');
console.log('7. Focus visibility ensured');
console.log('8. aria-required added to required fields');
console.log('9. Autocomplete attributes added');
console.log('10. aria-hidden added to decorative SVGs');
console.log('11. aria-labelledby added to form inputs');
console.log('12. role="navigation" and aria-label added to navs');
console.log('13. aria-label fixed for empty link text');
});
})();