Drupal Accessibility Checklist 2026 | WCAG 2.1 AA & EAA Compliance
Last updated: 2026-03-22
Drupal has long been recognized as one of the most accessibility-conscious content management systems available. The Drupal core team maintains a dedicated accessibility gate on all core commits, meaning that no code change can be merged into Drupal core without passing accessibility review. Drupal includes built-in features such as ARIA landmarks in default themes, proper heading hierarchy, and an accessible admin interface. However, the real-world accessibility of a Drupal site depends heavily on the contributed modules installed, the custom theme used, and the content authoring practices followed by editors. Many contributed modules do not undergo the same rigorous accessibility review as core, and custom Twig templates can easily introduce semantic HTML errors, missing labels, and keyboard navigation barriers. With the European Accessibility Act now being enforced across EU member states, Drupal site owners must audit their entire stack including core configuration, contributed modules, custom themes, and editor workflows. This checklist identifies the most common accessibility pitfalls specific to Drupal and provides concrete remediation steps that developers, site builders, and content editors can implement immediately.
Common Accessibility Issues
Drupal image fields have an optional alt text subfield, but many content types are configured with alt text not required, allowing editors to upload images without providing alternative text. The default image formatter may render images with no alt attribute at all if the field is empty, making informative images completely invisible to screen reader users.
Navigate to the content type field settings and set the alt text field as required for all image fields (Admin > Structure > Content Types > [Type] > Manage Fields > Image Field > Edit). In your Twig templates, always output the alt attribute even when the value is empty to ensure decorative images get an empty alt. For responsive images using the Responsive Image module, verify the alt text carries through to the rendered picture element.
{# Twig template missing alt text handling #}
<img src="{{ file_url(node.field_image.entity.fileuri) }}" class="hero-image"> {# Twig template with proper alt text handling #}
{% if node.field_image.alt %}
<img src="{{ file_url(node.field_image.entity.fileuri) }}"
alt="{{ node.field_image.alt }}"
class="hero-image">
{% else %}
<img src="{{ file_url(node.field_image.entity.fileuri) }}"
alt=""
role="presentation"
class="hero-image">
{% endif %} The Views module is used extensively in Drupal to create lists of content, but many Views displays output content as unstyled div containers without any semantic structure. Content listings that are conceptually lists are not wrapped in ul/ol elements, table displays may lack proper th and scope attributes, and grid layouts often use CSS-only positioning without any logical reading order.
In the Views UI, select appropriate row and style settings. Use 'HTML List' format for list-based displays to generate proper ul/li markup. For table displays, ensure header columns use the correct settings to render as th elements with scope attributes. Override Views templates (views-view--[name].html.twig) when built-in format options are insufficient, adding proper ARIA roles and semantic HTML.
<div class="view-content">
<div class="views-row">Article Title 1</div>
<div class="views-row">Article Title 2</div>
<div class="views-row">Article Title 3</div>
</div> <div class="view-content" role="region" aria-label="Recent articles">
<ul class="views-list">
<li class="views-row"><a href="/article-1">Article Title 1</a></li>
<li class="views-row"><a href="/article-2">Article Title 2</a></li>
<li class="views-row"><a href="/article-3">Article Title 3</a></li>
</ul>
</div> Drupal uses CKEditor for WYSIWYG content editing, and editors frequently select heading levels based on visual appearance rather than document structure. The CKEditor toolbar may also be configured to allow heading levels that break the page hierarchy, such as offering H1 when the page title already uses H1.
Configure the CKEditor profile (Admin > Configuration > Content Authoring > Text formats and editors) to remove H1 from available heading options since the page template should handle the H1. Provide training documentation for content editors explaining heading hierarchy. Consider installing the Editoria11y module which provides real-time accessibility warnings in the content editing interface.
Some Drupal contributed modules and admin themes implement modal dialogs that trap keyboard focus, preventing users from closing the dialog or returning to the main content using the Escape key or Tab key. This is particularly common in media browser modules, entity browser, and custom admin interfaces that use jQuery UI dialogs without proper focus management.
Audit all modal dialog implementations across your modules. Ensure that pressing Escape closes the dialog, that focus is trapped within the dialog while it is open (cycling from last to first focusable element), and that focus returns to the triggering element when the dialog closes. For jQuery UI dialogs, Drupal core provides accessible dialog handling through the core/drupal.dialog library. Use it instead of custom implementations.
While Drupal core Form API generates properly labeled form elements, many contributed modules and custom forms bypass the Form API or use render arrays incorrectly, resulting in form inputs without associated label elements. Search forms, filter forms, and inline editing interfaces are common offenders. This makes it impossible for screen reader users to understand what information each field requires.
Always use Drupal's Form API (#type, #title, #description) which automatically generates proper label associations. If the label should be visually hidden, add '#title_display' => 'invisible' to the form element rather than omitting the title. For search forms, add an aria-label to the input if a visible label is not part of the design. Audit contributed modules using browser developer tools to check for orphaned input elements.
$form['search'] = [
'#type' => 'textfield',
'#attributes' => ['placeholder' => 'Search...'],
];
$form['submit'] = [
'#type' => 'submit',
'#value' => '',
'#attributes' => ['class' => ['search-icon']],
]; $form['search'] = [
'#type' => 'textfield',
'#title' => t('Search'),
'#title_display' => 'invisible',
'#attributes' => ['placeholder' => 'Search...'],
];
$form['submit'] = [
'#type' => 'submit',
'#value' => t('Search'),
]; While Drupal's default themes (Olivero, Claro) meet WCAG contrast requirements, many contributed and custom themes use low-contrast color schemes. Light gray text on white backgrounds, low-contrast link colors that blend with body text, and placeholder text that fails minimum contrast ratios are common problems.
Audit your theme's color palette using a contrast checking tool. Every text element must meet at least 4.5:1 contrast ratio for normal text and 3:1 for large text (18px bold or 24px regular). Update your theme's CSS variables or SCSS variables to use colors that meet these ratios. If using Olivero's color settings, verify that custom color overrides maintain sufficient contrast.
Drupal's AJAX framework dynamically updates page regions in response to user actions, such as adding items to a cart, submitting AJAX forms, or loading more content. These updates are often not communicated to screen reader users because the updated DOM regions lack appropriate ARIA live region attributes.
When implementing AJAX callbacks, use Drupal's built-in AjaxResponse commands that include proper screen reader announcements. Add aria-live='polite' to regions that receive dynamic content updates. Use the Drupal.announce() JavaScript function to programmatically announce status messages to assistive technologies. This function is part of Drupal core and handles debouncing and priority automatically.
Drupal-Specific Tips
- Install the Editoria11y module (drupal.org/project/editoria11y) which adds real-time accessibility checking directly in the content editing interface, alerting editors to missing alt text, broken heading hierarchy, and other common issues before they publish.
- Use Drupal's built-in Olivero front-end theme as a starting point for custom themes, as it was designed with accessibility as a core requirement and includes proper ARIA landmarks, skip links, responsive navigation with keyboard support, and high-contrast mode.
- Leverage Drupal's Form API consistently for all custom forms rather than writing raw HTML, as it automatically generates proper label associations, error handling, required field indicators, and fieldset groupings that meet WCAG requirements.
- Enable Drupal's built-in announcement system by calling Drupal.announce() in your custom JavaScript whenever dynamic content updates occur, ensuring screen reader users are informed of changes without requiring a page reload.
- Run regular accessibility audits using the Drupal Accessibility Scanner module in combination with external tools like axe DevTools, and include these checks in your CI/CD pipeline before deploying to production.
Recommended Tools
Editoria11y
A real-time accessibility checker for Drupal content editors that highlights issues like missing alt text, heading hierarchy problems, and link text issues directly on the page while editing.
Drupal Accessibility Scanner
Integrates automated accessibility scanning into your Drupal site, running axe-core tests against your pages and reporting WCAG violations through the Drupal admin interface.
Axe DevTools Browser Extension
A browser extension by Deque Systems that performs comprehensive accessibility audits on any page, providing detailed WCAG violation reports with remediation guidance specific to the HTML output.
Further Reading
Other CMS Checklists
Get our free accessibility toolkit
We're building a simple accessibility checker for non-developers. Join the waitlist for early access and a free EAA compliance checklist.
No spam. Unsubscribe anytime.