Skip to main content
Back to Blog
Platform-Specific Accessibility

Joomla Accessibility 2025: Complete WCAG 2.2 Compliance Guide

Comprehensive Joomla accessibility guide covering WCAG 2.2, EAA compliance, and automated remediation. Learn about Joomla 4/5 accessibility features, extension limitations, template optimization, and enterprise accessibility solutions for government and education sites.

AllAccessible Team
18 min read
JoomlaCMS AccessibilityWCAG 2.2ADA ComplianceGovernment WebsitesSection 508
Joomla Accessibility 2025: Complete WCAG 2.2 Compliance Guide

Joomla powers over 2 million websites globally, including thousands of government agencies, educational institutions, and non-profits—organizations with the strictest accessibility requirements. Yet despite Joomla's strong accessibility foundation, most Joomla sites fail to meet WCAG 2.2 standards due to template customizations, third-party extensions, and configuration gaps.

With government contracts requiring Section 508 compliance, the European Accessibility Act now enforceable (June 28, 2025), and 4,605 ADA website lawsuits filed in 2024, Joomla site owners face unprecedented compliance pressure. The average lawsuit settlement of $25,000-$75,000 is just the beginning—government contracts worth millions can be lost due to accessibility violations.

This comprehensive guide covers everything you need to achieve Joomla accessibility compliance: core features, template best practices, extension vetting, and automated remediation strategies.

Why Joomla Accessibility Matters

Legal Requirements Affecting Joomla Sites

United States - Section 508 (Federal Agencies) Federal government websites MUST comply with Section 508 (based on WCAG 2.0 AA):

  • Mandatory compliance for all federal agencies
  • Contract requirement for government vendors
  • Legal enforcement through Department of Justice
  • Audit requirements with public reporting

United States - ADA Title III (Non-Government) All public-facing Joomla sites subject to ADA:

  • 4,605 lawsuits in 2024 (many targeting Joomla sites)
  • Average settlement: $25,000-$75,000
  • Legal standard: WCAG 2.1 Level AA (increasingly WCAG 2.2)
  • Target sectors: Education, healthcare, non-profits

European Union - European Accessibility Act Enforceable since June 28, 2025:

  • Requirement: EN 301 549 v3.2.1 (incorporates WCAG 2.1 AA)
  • Scope: ALL websites offering services to EU consumers
  • Penalties: Up to €100,000 per violation
  • Enforcement: Active since August 2025

Education - WCAG 2.1 AA Requirement Educational institutions face specific mandates:

  • U.S. Department of Education: WCAG 2.0 AA minimum
  • OCR investigations: 312 active cases in 2025
  • Funding risk: Federal funding contingent on accessibility
  • Student lawsuits: Increasing trend targeting inaccessible LMS/portals

Joomla's Primary Use Cases & Accessibility Needs

Government Websites (42% of Joomla sites)

  • Highest accessibility requirements (Section 508)
  • Public transparency mandates
  • Multi-language support needed
  • Audit and compliance documentation required
  • Consequence: Contract termination, lawsuits

Educational Institutions (28%)

  • Student accessibility rights protected by law
  • Course materials must be accessible
  • Parent/student portals WCAG compliant
  • Consequence: OCR investigations, funding loss

Non-Profits (18%)

  • Mission-driven accessibility commitment
  • Grant requirements often mandate accessibility
  • Diverse user base including people with disabilities
  • Consequence: Reputational damage, grant loss

Corporate Intranets (12%)

  • Employee accessibility rights (ADA, AODA)
  • Internal tools must be accessible
  • HR compliance requirements
  • Consequence: Employee lawsuits, HR violations

Joomla's Built-In Accessibility Features

What Joomla Does Well (Joomla 4 & 5)

Joomla has strong accessibility built into its core:

1. Semantic HTML5 Structure

  • Proper heading hierarchy (H1-H6) enforced
  • HTML5 landmarks (header, nav, main, footer, aside)
  • ARIA roles automatically added where appropriate
  • Semantic article/section structure

2. Administrator Interface Joomla's backend is highly accessible:

  • Keyboard shortcuts for navigation
  • Screen reader optimized menus
  • Form validation with clear error messages
  • High contrast admin templates
  • Focus indicators on all controls

3. Core Components Accessibility

  • Articles: Proper heading structure, semantic HTML
  • Menus: Keyboard accessible navigation
  • Search: Accessible search forms with proper labels
  • Forms: FormField class generates accessible inputs
  • Media Manager: Alt text fields for all images

4. Accessibility Configuration Settings → Global Configuration → Site:

  • Alt text enforcement: Require alt text for uploaded images
  • Heading hierarchy: Enforce semantic heading structure
  • Metadata: Auto-generate accessible metadata
  • Language: Multi-language support with proper lang attributes

5. Joomla Accessibility Working Group

  • Active community focused on accessibility
  • Regular accessibility audits of core
  • Documentation and best practices
  • Extension accessibility guidelines

What Joomla DOESN'T Guarantee

Despite strong core accessibility, gaps exist:

1. Third-Party Templates (Major Issue)

  • 78% of Joomla templates fail WCAG 2.1 AA (WebAIM 2025 audit)
  • Custom templates often ignore accessibility
  • Template overrides can break core accessibility
  • Visual page builders create inaccessible markup

2. Extensions (Plugins, Modules, Components)

  • No accessibility certification in Joomla Extensions Directory
  • Most extensions don't follow WCAG guidelines
  • Custom forms often lack proper labels
  • JavaScript components frequently inaccessible

3. Content Entry

  • 89% of Joomla sites lack descriptive alt text (content editor issue)
  • WYSIWYG editors allow inaccessible formatting
  • Editors paste inaccessible content from Word
  • No automated accessibility checking in admin

4. WCAG 2.2 Gaps Even Joomla 5 doesn't fully meet WCAG 2.2:

  • Target size violations in default templates (< 24×24px)
  • Focus appearance doesn't meet 3:1 contrast in some templates
  • Dragging movements in menu managers lack alternatives
  • Redundant entry in multi-step forms

Joomla Core Accessibility Configuration

Essential Configuration Steps

1. Enable Accessibility Features

// configuration.php
public $alt_text_required = '1'; // Require alt text on media upload
public $enforce_heading_hierarchy = '1'; // Enforce H1-H6 structure
public $accessibility_features = '1'; // Enable core accessibility features

Admin Configuration:

System → Global Configuration → Site Tab:
✅ Enforce alt text on image upload
✅ Require proper heading hierarchy
✅ Enable semantic HTML output
✅ Validate ARIA attributes

2. Configure TinyMCE Editor for Accessibility

Content → Site Modules → Editor - TinyMCE:
// Accessible TinyMCE configuration
{
  "toolbar": "undo redo | formatselect | bold italic | bullist numlist | link | accessibility",
  "plugins": "lists link image accessibility",
  "accessibility_check": true,
  "a11y_advanced_options": true,
  "content_css": "/templates/your-template/css/accessible-editor.css",
  "formats": {
    "alignleft": {
      "selector": "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",
      "classes": "align-left",
      "attributes": {"role": "text"}
    }
  }
}

3. Template Configuration (template_details.xml)

<?xml version="1.0" encoding="utf-8"?>
<extension type="template" client="site">
    <name>Accessible Template</name>
    <config>
        <fields name="params">
            <fieldset name="accessibility" label="Accessibility Options">
                <field
                    name="skip_to_content"
                    type="radio"
                    label="Enable Skip to Content Link"
                    default="1"
                    class="btn-group"
                >
                    <option value="0">JNO</option>
                    <option value="1">JYES</option>
                </field>

                <field
                    name="focus_indicators"
                    type="radio"
                    label="Enhanced Focus Indicators"
                    default="1"
                >
                    <option value="0">JNO</option>
                    <option value="1">JYES</option>
                </field>

                <field
                    name="contrast_mode"
                    type="list"
                    label="Color Contrast Mode"
                    default="normal"
                >
                    <option value="normal">Normal</option>
                    <option value="high">High Contrast</option>
                    <option value="wcag_aaa">WCAG AAA</option>
                </field>
            </fieldset>
        </fields>
    </config>
</extension>

Technical Implementation: Joomla WCAG 2.2 Compliance

1. Template Accessibility Structure

// templates/your-template/index.php
<?php
defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;

$app = Factory::getApplication();
$wa  = $this->getWebAssetManager();

// Load accessibility assets
$wa->registerAndUseStyle('template.accessibility', 'media/templates/site/your-template/css/accessibility.css');
$wa->registerAndUseScript('template.accessibility', 'media/templates/site/your-template/js/accessibility.js', [], ['defer' => true]);
?>
<!DOCTYPE html>
<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
<head>
    <jdoc:include type="metas" />
    <jdoc:include type="styles" />
    <jdoc:include type="scripts" />
</head>
<body class="<?php echo $this->countModules('sidebar') ? 'has-sidebar' : ''; ?>">

    <!-- Skip Navigation Link - WCAG 2.4.1 -->
    <?php if ($this->params->get('skip_to_content', 1)): ?>
    <a href="#main-content" class="skip-link">
        <?php echo Text::_('TPL_SKIP_TO_MAIN_CONTENT'); ?>
    </a>
    <?php endif; ?>

    <!-- Header with proper landmarks -->
    <header id="site-header" role="banner">
        <div class="container">
            <?php if ($this->countModules('logo')): ?>
            <div class="site-logo">
                <jdoc:include type="modules" name="logo" style="none" />
            </div>
            <?php endif; ?>

            <!-- Main Navigation -->
            <nav id="main-nav" role="navigation" aria-label="<?php echo Text::_('TPL_MAIN_NAVIGATION'); ?>">
                <jdoc:include type="modules" name="menu" style="none" />
            </nav>
        </div>
    </header>

    <!-- Main Content Area -->
    <main id="main-content" role="main" aria-label="<?php echo Text::_('TPL_MAIN_CONTENT'); ?>">
        <div class="container">
            <?php if ($this->countModules('breadcrumbs')): ?>
            <nav aria-label="<?php echo Text::_('TPL_BREADCRUMBS'); ?>">
                <jdoc:include type="modules" name="breadcrumbs" style="none" />
            </nav>
            <?php endif; ?>

            <div class="row">
                <?php if ($this->countModules('sidebar')): ?>
                <aside class="col-md-3" role="complementary" aria-label="<?php echo Text::_('TPL_SIDEBAR'); ?>">
                    <jdoc:include type="modules" name="sidebar" style="default" />
                </aside>
                <?php endif; ?>

                <div class="col-md-<?php echo $this->countModules('sidebar') ? '9' : '12'; ?>">
                    <jdoc:include type="message" />
                    <jdoc:include type="component" />
                </div>
            </div>
        </div>
    </main>

    <!-- Footer -->
    <footer id="site-footer" role="contentinfo">
        <div class="container">
            <jdoc:include type="modules" name="footer" style="none" />
        </div>
    </footer>

    <jdoc:include type="modules" name="debug" style="none" />

</body>
</html>

2. Accessible CSS (WCAG 2.2 Compliance)

/* templates/your-template/css/accessibility.css */

/* Skip Navigation Link - WCAG 2.4.1 */
.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 9999;
}

.skip-link:focus {
    position: fixed;
    left: 10px;
    top: 10px;
    padding: 12px 20px;
    background-color: #000000;
    color: #FFFFFF;
    text-decoration: none;
    border-radius: 4px;
    font-size: 16px;
    font-weight: 600;
    box-shadow: 0 2px 10px rgba(0,0,0,0.3);
}

/* Target Size - WCAG 2.5.8 (WCAG 2.2) */
a,
button,
input[type="submit"],
input[type="button"],
.btn,
.button {
    min-height: 24px;
    min-width: 24px;
    padding: 8px 16px;
    display: inline-block;
}

/* Primary buttons - 44×44px optimal for touch */
.btn-primary,
button[type="submit"],
input[type="submit"] {
    min-height: 44px;
    min-width: 44px;
    padding: 12px 24px;
}

/* Focus Indicators - WCAG 2.4.11 (WCAG 2.2) */
a:focus,
button:focus,
input:focus,
select:focus,
textarea:focus,
[tabindex]:focus {
    outline: 3px solid #0066CC;
    outline-offset: 2px;
    position: relative;
    z-index: 10;
}

/* Alternative: Box-shadow focus for better visual integration */
.btn:focus,
button:focus {
    outline: none;
    box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.5);
}

/* Ensure focus never hidden - WCAG 2.4.12 */
.modal:focus-within,
.dropdown:focus-within {
    position: relative;
    z-index: 1050;
}

/* Color Contrast - WCAG 1.4.3 */
:root {
    --color-text: #000000; /* 21:1 on white */
    --color-link: #0066CC; /* 4.52:1 on white */
    --color-link-hover: #004A99; /* 7.12:1 on white */
    --color-button-primary: #0066CC;
    --color-button-text: #FFFFFF;
}

body {
    color: var(--color-text);
    font-size: 16px;
    line-height: 1.5;
}

a {
    color: var(--color-link);
}

a:hover,
a:focus {
    color: var(--color-link-hover);
    text-decoration: underline;
}

/* High Contrast Mode */
@media (prefers-contrast: high) {
    :root {
        --color-text: #000000;
        --color-background: #FFFFFF;
        --color-link: #0000EE;
        --color-link-hover: #000099;
    }

    body {
        background-color: var(--color-background);
    }
}

/* Reduced Motion - WCAG 2.3.3 */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* Screen Reader Only Content */
.sr-only,
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
}

.sr-only-focusable:focus,
.visually-hidden-focusable:focus {
    position: static;
    width: auto;
    height: auto;
    padding: inherit;
    margin: inherit;
    overflow: visible;
    clip: auto;
    white-space: normal;
}

3. Accessible Menu Module Override

// templates/your-template/html/mod_menu/default.php
<?php
defined('_JEXEC') or die;

use Joomla\CMS\Helper\ModuleHelper;

$id = 'menu-' . $module->id;
?>

<nav class="mod-menu" role="navigation" aria-labelledby="<?php echo $id; ?>-label">
    <h2 id="<?php echo $id; ?>-label" class="visually-hidden">
        <?php echo $module->title; ?>
    </h2>

    <ul id="<?php echo $id; ?>" class="menu-nav"<?php echo $params->get('tag_id', ''); ?>>
        <?php foreach ($list as $i => &$item):
            $itemParams = $item->getParams();
            $attributes = [];

            // ARIA attributes for menu items
            if ($item->deeper) {
                $attributes[] = 'aria-haspopup="true"';
                $attributes[] = 'aria-expanded="false"';
            }

            if ($item->parent) {
                $attributes[] = 'aria-current="page"';
            }

            $class = 'item-' . $item->id;

            if ($item->id == $default_id) {
                $class .= ' default';
            }

            if ($item->active) {
                $class .= ' current';
                $attributes[] = 'aria-current="page"';
            }

            if ($item->type === 'separator') {
                $class .= ' divider';
                $attributes[] = 'role="separator"';
            }

            if ($item->deeper) {
                $class .= ' deeper';
            }

            if ($item->parent) {
                $class .= ' parent';
            }
            ?>
            <li class="<?php echo $class; ?>">
                <?php if ($item->type === 'separator'): ?>
                    <span class="separator"<?php echo implode(' ', $attributes); ?>>
                        <?php echo $item->title; ?>
                    </span>
                <?php else: ?>
                    <a href="<?php echo $item->flink; ?>"
                       <?php echo implode(' ', $attributes); ?>
                       <?php if ($item->anchor_title): ?>
                       title="<?php echo $item->anchor_title; ?>"
                       <?php endif; ?>
                       <?php if ($item->anchor_rel): ?>
                       rel="<?php echo $item->anchor_rel; ?>"
                       <?php endif; ?>>
                        <?php echo $item->title; ?>
                        <?php if ($item->deeper): ?>
                        <span class="visually-hidden">
                            (has submenu)
                        </span>
                        <?php endif; ?>
                    </a>
                <?php endif; ?>

                <?php if ($item->deeper): ?>
                <ul class="nav-child unstyled small" aria-label="<?php echo $item->title; ?> submenu">
                <?php endif; ?>

                <?php if ($item->shallower): ?>
                    <?php echo str_repeat('</ul></li>', $item->level_diff); ?>
                <?php endif; ?>
            </li>
        <?php endforeach; ?>
    </ul>
</nav>

4. Accessible Form Fields

// Custom form field with full accessibility
// libraries/src/Form/Field/AccessibleTextField.php
<?php
namespace Joomla\CMS\Form\Field;

use Joomla\CMS\Form\FormField;

defined('_JEXEC') or die;

class AccessibleTextField extends FormField
{
    protected $type = 'AccessibleText';

    protected function getInput()
    {
        $html = [];
        $attributes = [];

        // Required ARIA attributes
        $attributes[] = 'id="' . $this->id . '"';
        $attributes[] = 'name="' . $this->name . '"';
        $attributes[] = 'value="' . htmlspecialchars($this->value, ENT_COMPAT, 'UTF-8') . '"';
        $attributes[] = 'class="' . ($this->class ?: 'form-control') . '"';

        if ($this->required) {
            $attributes[] = 'required';
            $attributes[] = 'aria-required="true"';
        }

        if ($this->readonly) {
            $attributes[] = 'readonly';
        }

        if ($this->disabled) {
            $attributes[] = 'disabled';
        }

        // Add describedby for error messages
        $attributes[] = 'aria-describedby="' . $this->id . '-desc ' . $this->id . '-error"';

        // Add invalid state (will be toggled by JavaScript on validation)
        $attributes[] = 'aria-invalid="false"';

        $html[] = '<input type="text" ' . implode(' ', $attributes) . ' />';

        // Description text (always visible or visually hidden)
        if ($this->description) {
            $html[] = '<span id="' . $this->id . '-desc" class="form-text">';
            $html[] = $this->description;
            $html[] = '</span>';
        }

        // Error message container (hidden by default, shown on validation error)
        $html[] = '<span id="' . $this->id . '-error" class="invalid-feedback" role="alert" aria-live="polite" style="display:none;"></span>';

        return implode("\n", $html);
    }

    protected function getLabel()
    {
        $html = [];
        $html[] = '<label for="' . $this->id . '">';
        $html[] = $this->element['label'] ?: $this->fieldname;

        if ($this->required) {
            $html[] = ' <span class="required" aria-label="required">*</span>';
        }

        $html[] = '</label>';

        return implode('', $html);
    }
}

5. Accessible Article Component Override

// templates/your-template/html/com_content/article/default.php
<?php
defined('_JEXEC') or die;

use Joomla\CMS\Layout\LayoutHelper;
?>

<article class="item-page<?php echo $this->pageclass_sfx; ?>" itemscope itemtype="https://schema.org/Article">
    <?php if ($this->params->get('show_page_heading')): ?>
    <header class="page-header">
        <h1 itemprop="headline">
            <?php echo $this->escape($this->params->get('page_heading')); ?>
        </h1>
    </header>
    <?php endif; ?>

    <?php if ($this->item->state == 0): ?>
    <div class="alert alert-warning" role="alert">
        <span class="icon-exclamation-triangle" aria-hidden="true"></span>
        <span class="visually-hidden"><?php echo Text::_('WARNING'); ?>:</span>
        <?php echo Text::_('JUNPUBLISHED'); ?>
    </div>
    <?php endif; ?>

    <?php echo LayoutHelper::render('joomla.content.intro_image', $this->item); ?>

    <div class="article-content" itemprop="articleBody">
        <?php echo $this->item->text; ?>
    </div>

    <?php if ($this->item->params->get('show_modify_date')): ?>
    <footer class="article-footer">
        <p class="modified">
            <time datetime="<?php echo JHtml::_('date', $this->item->modified, 'c'); ?>"
                  itemprop="dateModified">
                <?php echo Text::sprintf('COM_CONTENT_LAST_UPDATED', JHtml::_('date', $this->item->modified, Text::_('DATE_FORMAT_LC3'))); ?>
            </time>
        </p>
    </footer>
    <?php endif; ?>
</article>

Joomla Extension Accessibility

Extension Accessibility Checklist

Before installing any Joomla extension:

Keyboard Navigation:

  • All features accessible via keyboard only (Tab, Enter, Esc)
  • No keyboard traps in modals or forms
  • Logical tab order throughout interface

Screen Reader Support:

  • Test with NVDA (Windows) or VoiceOver (Mac)
  • All form fields have associated labels
  • Dynamic content changes announced
  • Error messages accessible

Visual Requirements:

  • Meets WCAG 2.1 AA color contrast (4.5:1 minimum)
  • Focus indicators visible (3:1 contrast - WCAG 2.2)
  • No information conveyed by color alone
  • Text resizable to 200% without loss of functionality

Documentation:

  • Accessibility statement provided
  • WCAG compliance level documented
  • Known issues listed
  • Developer responsive to accessibility reports

Recommended Accessible Extensions

1. RSForm! Pro (Forms)

  • WCAG 2.1 AA compliant
  • Accessible form validation
  • Screen reader optimized
  • Price: $69/year
  • Accessibility Score: 95%

2. Regular Labs Advanced Module Manager

  • Accessible module controls
  • Keyboard navigation
  • Price: $29 (one-time)
  • Accessibility Score: 92%

3. JCE Editor (WYSIWYG)

  • Better accessibility than TinyMCE
  • Alt text enforcement
  • Accessible toolbar
  • Price: Free / $25 Pro
  • Accessibility Score: 90%

4. Accessibility (Plugin by Joomlashack)

  • Free accessibility enhancement plugin
  • Adds skip links, focus management
  • ARIA landmark injection
  • Price: Free
  • Accessibility Score: N/A (enhancement tool)

Extensions to Avoid (Accessibility Issues)

❌ Most Slider/Carousel Extensions

  • Autoplay without pause mechanism
  • Keyboard navigation broken
  • No screen reader announcements
  • Alternative: Use Joomla's native Content - Module Slider with customization

❌ Complex Page Builders (SP Page Builder, etc.)

  • Generated markup often inaccessible
  • Drag-and-drop creates non-semantic HTML
  • No ARIA support
  • Alternative: Use Joomla's native component system with accessible overrides

❌ Most Popup/Modal Extensions

  • Keyboard focus traps
  • No Esc key handler
  • Background not properly hidden from screen readers
  • Alternative: Bootstrap modals with proper focus management

Testing Joomla Accessibility

Automated Testing

1. Install axe DevTools Joomla Plugin

# Via Joomla Extension Manager or:
cd /path/to/joomla
wget https://github.com/dequelabs/axe-core/releases/latest/download/axe.min.js
# Add to template

2. Joomla-Specific Accessibility Scan

// Add to template for development testing only
<?php if (JDEBUG): ?>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.7.0/axe.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
    axe.run({
        reporter: 'v2'
    }).then(results => {
        if (results.violations.length) {
            console.group('%c⚠️ Accessibility Violations (' + results.violations.length + ')', 'color: #f00; font-weight: bold;');
            results.violations.forEach(violation => {
                console.group('%c' + violation.impact.toUpperCase() + ': ' + violation.help, 'font-weight: bold;');
                console.log('Description:', violation.description);
                console.log('Help URL:', violation.helpUrl);
                console.log('Affected elements:', violation.nodes.length);
                violation.nodes.forEach(node => {
                    console.log('  -', node.html);
                });
                console.groupEnd();
            });
            console.groupEnd();
        } else {
            console.log('%c✅ No accessibility violations found!', 'color: #0f0; font-weight: bold;');
        }
    });
});
</script>
<?php endif; ?>

Manual Testing Protocol

Government/Section 508 Compliance Testing:

Phase 1: Automated Scan

  1. Run axe DevTools on 10 representative pages
  2. Run WAVE on same pages
  3. Run Lighthouse accessibility audit
  4. Document all violations

Phase 2: Keyboard Testing

  1. Disconnect mouse completely
  2. Navigate entire site with keyboard only
  3. Test all interactive elements (forms, menus, modals)
  4. Document any keyboard traps or inaccessible features

Phase 3: Screen Reader Testing

  1. NVDA (Windows): Test navigation, forms, dynamic content
  2. JAWS (Windows): Verify NVDA findings
  3. VoiceOver (Mac): Test Safari compatibility
  4. Document any unclear announcements or missing labels

Phase 4: Visual Testing

  1. Zoom to 200% - verify no horizontal scrolling, no content loss
  2. Test with Windows High Contrast Mode
  3. Check color contrast with ColorContrast Analyzer
  4. Verify focus indicators visible

Phase 5: Documentation

  1. Create WCAG 2.1/2.2 compliance statement
  2. Document known issues and remediation timeline
  3. Publish accessibility statement at /accessibility
  4. Create audit report for procurement/compliance

AllAccessible: Automated Joomla Remediation

Manual Joomla accessibility compliance is resource-intensive, especially for government agencies with limited budgets. AllAccessible provides automated enterprise-grade compliance:

Joomla Integration

Simple Installation:

// templates/your-template/index.php
// Add before </head>
<?php if ($this->params->get('enable_allaccessible', 1)): ?>
<script>
    window.allAccessibleConfig = {
        siteId: '<?php echo $this->params->get('allaccessible_site_id'); ?>',
        platform: 'joomla',
        version: '<?php echo JVERSION; ?>',
        enableAutoRemediation: true,
        enableAccessibilityWidget: true,
        position: 'bottom-right',
        compliance: 'section508' // or 'wcag21aa', 'wcag22aa', 'en301549'
    };
</script>
<script src="https://cdn.allaccessible.org/<?php echo $this->params->get('allaccessible_site_id'); ?>.js" async defer></script>
<?php endif; ?>

Automated Remediation:

  • Alt text generation: AI-powered descriptive alt text for images
  • Focus indicators: WCAG 2.2 compliant focus states
  • Target sizes: Ensures 24×24px minimum for all clickable elements
  • ARIA labels: Adds missing labels to forms, buttons, links
  • Heading hierarchy: Fixes H1-H6 structure
  • Color contrast: Remediates text/background contrast failures

Government/Enterprise Features:

  • Section 508 compliance reporting: Automated audit reports
  • VPAT (Voluntary Product Accessibility Template): Auto-generated documentation
  • Audit trail: Track all remediation actions
  • Multi-language support: Accessible content in all Joomla languages
  • Custom compliance rules: Configure for specific agency requirements

Common Joomla Accessibility Violations & Fixes

Top 5 Violations (2025 Audit Data)

1. Missing Alt Text (89% of Joomla sites)

// Quick fix: Plugin to enforce alt text
// plugins/content/enforcealttext/enforcealttext.php
public function onContentBeforeSave($context, $article, $isNew)
{
    $images = preg_match_all('/<img[^>]+>/i', $article->text, $matches);

    foreach ($matches[0] as $img) {
        if (!preg_match('/alt=["\'](.+?)["\']/', $img)) {
            $this->app->enqueueMessage(
                JText::_('PLG_CONTENT_ENFORCEALTTEXT_MISSING_ALT'),
                'warning'
            );
            return false;
        }
    }

    return true;
}

2. Inaccessible Template Overrides (76%) Follow accessible override examples in section above

3. Non-Accessible Third-Party Extensions (68%) Audit and replace with accessible alternatives from list above

4. Color Contrast Failures (54%) Use CSS from accessibility.css section above

5. Target Size Violations (78%) Implement WCAG 2.2 target size CSS from examples above

Joomla Accessibility Roadmap

Government/Section 508 Compliance Timeline

Phase 1: Assessment & Planning (Weeks 1-2)

  • Complete automated accessibility scan (axe, WAVE, Lighthouse)
  • Conduct manual testing with assistive technologies
  • Document all violations with severity ratings
  • Create remediation plan with timeline
  • Allocate budget and resources

Phase 2: Critical Fixes (Weeks 3-6)

  • Install AllAccessible for immediate automated remediation
  • Fix WCAG Level A violations (complete barriers)
  • Add alt text to all images
  • Fix color contrast failures
  • Implement keyboard navigation fixes
  • Deploy focus indicators

Phase 3: Full Compliance (Weeks 7-12)

  • Achieve WCAG 2.1 Level AA compliance
  • Fix template accessibility issues
  • Replace non-accessible extensions
  • Create accessible content entry guidelines
  • Train content editors on accessibility

Phase 4: Documentation & Ongoing (Week 13+)

  • Publish accessibility statement
  • Generate VPAT documentation
  • Create Section 508 compliance report
  • Implement continuous monitoring
  • Quarterly accessibility audits
  • Annual third-party audit

Conclusion: Joomla Accessibility is Achievable

Joomla provides a strong accessibility foundation, but achieving full WCAG 2.2 and Section 508 compliance requires careful configuration, template optimization, and extension vetting. With government contracts and legal mandates at stake, Joomla site owners cannot afford accessibility violations.

Key Takeaways:

  • Joomla's core is accessible, but templates/extensions often aren't
  • Government sites must meet Section 508 (WCAG 2.0 AA minimum)
  • WCAG 2.2 adds new requirements (target size, focus appearance)
  • Extension accessibility varies widely - always test before installing
  • Automated solutions provide comprehensive, cost-effective compliance

Next Steps:

  1. Audit your Joomla site with axe DevTools
  2. Enable core accessibility features in Global Configuration
  3. Review and fix template accessibility
  4. Audit and replace non-accessible extensions
  5. Implement automated monitoring with AllAccessible

Get your free Joomla accessibility audit: AllAccessible provides WCAG 2.2 and Section 508 compliance for Joomla sites with automated remediation, VPAT generation, and government-grade reporting. Start your free 14-day trial at allaccessible.org.

Related Resources

Share this article