Accessibility Pattern Report

Clustered axe-core issue patterns grouped by rule, selector similarity, and affected routes.

Source markdown: PATTERN-REPORT-latest.md

Drupal Core Accessibility Bug Report

Generated: 2026-05-06T16:22:36.086Z
Tool: axe-core via @axe-core/playwright | Browser: Chromium
Standard: ACCESSIBILITY_BUG_REPORTING_BEST_PRACTICES.md

Summary#

MetricValue
Pages crawled2193
Total violation instances5550
Unique patterns13
Template-level patterns (≥3 pages) 🔁10
Critical1
Serious4
Moderate6
Minor2

Project queue: https://www.drupal.org/project/issues/search?text=&projects=Drupal+core&assigned=&submitted=&project_issue_followers=&status%5B%5D=Open&issue_tags_op=%3D&issue_tags=Accessibility

Validated Keyboard Promotion Findings#

MetricValue
Promotion candidates (WCAG 2.5.3)2
Contract checks4
❌ Failures1
✅ Passes3
Results generated2026-04-29T18:00:08.808Z

❌ Label-in-Name Failures (Action Required)#

WCAG 2.5.3 — The accessible name of a control must contain the visible label text. Speech-input users who activate controls by speaking what they see will fail if these differ.

LABEL-IN-NAME-004: Configure action visible text appears in accessible name#

How to reproduce:

  1. Log into Drupal and navigate to /admin/config/content/formats
  2. Locate the element matching table tbody tr:has-text("Basic HTML") a:has-text("Configure")
  3. Inspect the element — the visible text reads "Configure"
  4. Check aria-label — it reads "Edit Basic HTML" which does not contain the visible text
  5. A speech-input user saying "click Configure" cannot activate this control

Fix: Update the aria-label to include the visible label text, or remove it if the visible text already provides a sufficient accessible name.

✅ Passing label-in-name checks (3) — click to expand
Contract IDRouteSelectorExpected Label
LABEL-IN-NAME-001/admin/form_style#edit-test-datelist-monthMonth
LABEL-IN-NAME-002/admin/form_style#edit-test-datelist-dayDay
LABEL-IN-NAME-003/admin/structure/types/addsummary:has-text("Submission form settings")Submission form settings
✅ Promotion candidates that passed validation (2) — click to expand
Candidate IDRouteFinding
PROMOTE-001/admin/form_style2 potential label-in-name mismatches in sampled focus steps.
PROMOTE-002/admin/structure/types/add1 potential label-in-name mismatches in sampled focus steps.

Aggregated Accessibility Issues by Category#

Form Interactions#

CSS and Presentation#

Input Modalities#

Other Accessibility Issues#

Semantic Structure#

Data Tables#

Reproducible Issue Details#

DRUPAL-A11Y-001—2026-05-06: label: Ensure every form element has a label#

Pattern ID: DRU-6CA3D5EB Rule: axe-core - label Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/label Severity: Critical (axe impact: critical) WCAG SC: 1.3.1 - Info and Relationships (Level A) Frequency: 4 of 2193 pages (0%) Selector: #edit-imagefile-file-limited-N-display XPath: //*[@id="edit-imagefile-file-limited-0-display"] Parent Context: N/A

Affected URLs (full list):

Conditions:

HTML Snippet#

<input class="file-display form-checkbox form-boolean form-boolean--type-checkbox" data-drupal-selector="edit-imagefile-file-limited-0-display" type="checkbox" id="edit-imagefile-file-limited-0-display" name="imagefile_file_limited[0][display]" value="1" checked="checked">

Description#

Fix any of the following: Element does not have an implicit (wrapped) <label> Element does not have an explicit <label> aria-label attribute does not exist or is empty aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty Element has no title attribute Element has no placeholder attribute Element's default semantics were not overridden with role="none" or role="presentation"

Steps to Reproduce#

  1. Go to https://drupal-core.ddev.site/contact/imagefile_file
  2. Use the matching context from Conditions: claro (dark desktop, dark mobile, light desktop, light mobile)
  3. Open browser DevTools and run axe.run() in the Console.
  4. Confirm rule label on selector #edit-imagefile-file-limited-N-display.

Expected Behaviour#

Element and interaction meet the mapped WCAG success criterion.

Actual Behaviour#

Fix any of the following: Element does not have an implicit (wrapped) <label> Element does not have an explicit <label> aria-label attribute does not exist or is empty aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty Element has no title attribute Element has no placeholder attribute Element's default semantics were not overridden with role="none" or role="presentation"

Impact#

blind, low-vision, voice-control

Suggested Fix#

See axe documentation.

Additional References#

Testing Environment#

Tracking IDs#

DRUPAL-A11Y-002—2026-05-06: color-contrast: Ensure the contrast between foreground and background colors meets WCAG 2 AA min#

Pattern ID: DRU-F75A07EF Rule: axe-core - color-contrast Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/color-contrast Severity: High (axe impact: serious) WCAG SC: 1.4.3 - Contrast (Minimum) (Level AA) Frequency: 176 of 2193 pages (8%) Selector: a[hreflang="he"] XPath: //a[@hreflang="he"] Parent Context: N/A

Affected URLs (full list):

Conditions:

HTML Snippet#

<a href="/he/action-link" class="language-link" hreflang="he" data-drupal-link-system-path="action-link">Hebrew</a>

Description#

Fix any of the following: Element has insufficient color contrast of 4.38 (foreground color: #c55228, background color: #fefaf8, font size: 12.0pt (16px), font weight: normal). Expected contrast ratio of 4.5:1

Steps to Reproduce#

  1. Go to https://drupal-core.ddev.site/action-link
  2. Use the matching context from Conditions: admin (light desktop, light mobile), claro (dark desktop, dark mobile, light desktop, light mobile)
  3. Open browser DevTools and run axe.run() in the Console.
  4. Confirm rule color-contrast on selector a[hreflang="he"].

Expected Behaviour#

Element and interaction meet the mapped WCAG success criterion.

Actual Behaviour#

Fix any of the following: Element has insufficient color contrast of 4.38 (foreground color: #c55228, background color: #fefaf8, font size: 12.0pt (16px), font weight: normal). Expected contrast ratio of 4.5:1

Impact#

low-vision

Suggested Fix#

Check foreground/background color combinations. Ensure ratio ≥ 4.5:1 for normal text, ≥ 3:1 for large text (18pt or 14pt bold). Update the relevant CSS file.

Additional References#

Testing Environment#

Tracking IDs#

DRUPAL-A11Y-003—2026-05-06: "Select all rows" checkbox is labeled only by its title attribute#

Pattern ID: DRU-987EB788 Rule: axe-core - label-title-only Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/label-title-only Severity: High (axe impact: serious) WCAG SC: 1.3.1 - Info and Relationships (Level A) Frequency: 14 of 2193 pages (1%) Selector: input[title="Select all rows in this table"] XPath: //input[@title="Select all rows in this table"] Parent Context: N/A

Affected URLs (full list):

Conditions:

HTML Snippet#

<input type="checkbox" class="form-checkbox form-boolean form-boolean--type-checkbox" title="Select all rows in this table">

Description#

Fix all of the following: Only title used to generate label for form element

Steps to Reproduce#

  1. Go to https://drupal-core.ddev.site/admin/content
  2. Use the matching context from Conditions: admin (light desktop, light mobile), claro (dark desktop, dark mobile, light desktop, light mobile)
  3. Open browser DevTools and run axe.run() in the Console.
  4. Confirm rule label-title-only on selector input[title="Select all rows in this table"].

Expected Behaviour#

Checkbox has a visible or visually-hidden <label>, or aria-label

Actual Behaviour#

input[title="Select all rows in this table"] — title is the sole label source

Impact#

blind, low-vision, voice-control

Suggested Fix#

Replace the title-only label with aria-label:

<!-- Before (broken) --> <input type="checkbox" title="{{ 'Select all rows in this table'|t }}">

<!-- After (fixed) --> <input type="checkbox" aria-label="{{ 'Select all rows in this table'|t }}">

Additional References#

Testing Environment#

Tracking IDs#

DRUPAL-A11Y-004—2026-05-06: tabindex: Ensure tabindex attribute values are not greater than 0#

Pattern ID: DRU-CC36FB25 Rule: axe-core - tabindex Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/tabindex Severity: High (axe impact: serious) WCAG SC: 2.4.3 - Focus Order (Level A) Frequency: 12 of 2193 pages (1%) Selector: #edit-submit XPath: //*[@id="edit-submit"] Parent Context: N/A

Affected URLs (full list):

Conditions:

HTML Snippet#

<input class="button button--primary js-form-submit form-submit" tabindex="1" data-drupal-selector="edit-submit" type="submit" id="edit-submit" name="op" value="Primary">

Description#

Fix any of the following: Element has a tabindex greater than 0

Steps to Reproduce#

  1. Go to https://drupal-core.ddev.site/buttons
  2. Use the matching context from Conditions: claro (dark desktop, dark mobile, light desktop, light mobile)
  3. Open browser DevTools and run axe.run() in the Console.
  4. Confirm rule tabindex on selector #edit-submit.

Expected Behaviour#

Element and interaction meet the mapped WCAG success criterion.

Actual Behaviour#

Fix any of the following: Element has a tabindex greater than 0

Impact#

users with disabilities

Suggested Fix#

See axe documentation.

Additional References#

Testing Environment#

Tracking IDs#

DRUPAL-A11Y-005—2026-05-06: summary-name: Ensure summary elements have discernible text#

Pattern ID: DRU-4422E904 Rule: axe-core - summary-name Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/summary-name Severity: High (axe impact: serious) WCAG SC: unknown - See axe docs (Level ?) Frequency: 1 of 2193 pages (0%) Selector: #edit-modules-nyan-cat-enable-description > .module-list__module-summary XPath: //*[@id="edit-modules-nyan-cat-enable-description > .module-list__module-summary"] Parent Context: N/A

Affected URLs (full list):

Conditions:

HTML Snippet#

<summary aria-controls="edit-modules-nyan-cat-enable-description" role="button" aria-expanded="false" class="gin-details__summary module-list__module-summary"><span class="text module-description"></span><span class="gin-details__summary-summary"></span></summary>

Description#

Fix any of the following: Element does not have text that is visible to screen readers aria-label attribute does not exist or is empty aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty Element has no title attribute

Steps to Reproduce#

  1. Go to https://drupal-core.ddev.site/admin/modules
  2. Use the matching context from Conditions: admin (light desktop), claro (dark desktop, light desktop)
  3. Open browser DevTools and run axe.run() in the Console.
  4. Confirm rule summary-name on selector #edit-modules-nyan-cat-enable-description > .module-list__module-summary.

Expected Behaviour#

Element and interaction meet the mapped WCAG success criterion.

Actual Behaviour#

Fix any of the following: Element does not have text that is visible to screen readers aria-label attribute does not exist or is empty aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty Element has no title attribute

Impact#

users with disabilities

Suggested Fix#

See axe documentation.

Additional References#

Testing Environment#

Tracking IDs#

DRUPAL-A11Y-006—2026-05-06: region: Ensure all page content is contained by landmarks#

Pattern ID: DRU-6BA9E02D Rule: axe-core - region Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/region Severity: Medium (axe impact: moderate) WCAG SC: 1.3.6 - Identify Purpose (Level A) Frequency: 128 of 2193 pages (6%) Selector: .themeswitcher-form__form-item XPath: //*[contains(@class,"themeswitcher-form__form-item")] Parent Context: N/A Likely Template: form-element.html.twig Template Hint: Form element template Drupal File: See likely_template above

Affected URLs (full list):

Conditions:

HTML Snippet#

<div class="themeswitcher-form__form-item js-form-item form-item js-form-type-select form-type--select js-form-item-preferred-theme form-item--preferred-theme">

Description#

Fix any of the following: Some page content is not contained by landmarks

Steps to Reproduce#

  1. This issue may require opening a dialog/off-canvas panel before running axe.
  2. Go to https://drupal-core.ddev.site/
  3. Use the matching context from Conditions: admin (light desktop, light mobile), claro (dark desktop, dark mobile, light desktop, light mobile), olivero (dark desktop, dark mobile, light desktop, light mobile)
  4. Open browser DevTools and run axe.run() in the Console.
  5. Confirm rule region on selector .themeswitcher-form__form-item.

Expected Behaviour#

Element and interaction meet the mapped WCAG success criterion.

Actual Behaviour#

Fix any of the following: Some page content is not contained by landmarks

Impact#

blind, low-vision

Suggested Fix#

Ensure all visible content is inside a landmark element (<main>, <nav>, <aside>, <header>, <footer>). Check page.html.twig and block placement.

Additional References#

Testing Environment#

Tracking IDs#

DRUPAL-A11Y-007—2026-05-06: landmark-contentinfo-is-top-level: Ensure the contentinfo landmark is at top level#

Pattern ID: DRU-2E022F2F Rule: axe-core - landmark-contentinfo-is-top-level Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/landmark-contentinfo-is-top-level Severity: Medium (axe impact: moderate) WCAG SC: 1.3.6 - Identify Purpose (Level A) Frequency: 20 of 2193 pages (1%) Selector: .messages--error XPath: //*[contains(@class,"messages--error")] Parent Context: N/A

Affected URLs (full list):

Conditions:

HTML Snippet#

<div role="contentinfo" aria-labelledby="message-error-title" class="messages-list__item messages messages--error">

Description#

Fix any of the following: The contentinfo landmark is contained in another landmark.

Steps to Reproduce#

  1. Go to https://drupal-core.ddev.site/admin/appearance
  2. Use the matching context from Conditions: admin (light desktop, light mobile), claro (dark desktop, dark mobile, light desktop, light mobile)
  3. Open browser DevTools and run axe.run() in the Console.
  4. Confirm rule landmark-contentinfo-is-top-level on selector .messages--error.

Expected Behaviour#

Element and interaction meet the mapped WCAG success criterion.

Actual Behaviour#

Fix any of the following: The contentinfo landmark is contained in another landmark.

Impact#

users with disabilities

Suggested Fix#

See axe documentation.

Additional References#

Testing Environment#

Tracking IDs#

Pattern ID: DRU-1260AB7D Rule: axe-core - landmark-no-duplicate-contentinfo Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/landmark-no-duplicate-contentinfo Severity: Medium (axe impact: moderate) WCAG SC: 1.3.6 - Identify Purpose (Level A) Frequency: 6 of 2193 pages (0%) Selector: .messages--error XPath: //*[contains(@class,"messages--error")] Parent Context: N/A

Affected URLs (full list):

Conditions:

HTML Snippet#

<div role="contentinfo" aria-labelledby="message-error-title" class="messages-list__item messages messages--error">

Description#

Fix any of the following: Document has more than one contentinfo landmark

Steps to Reproduce#

  1. Go to https://drupal-core.ddev.site/admin/appearance
  2. Use the matching context from Conditions: admin (light desktop, light mobile), claro (dark desktop, dark mobile, light desktop, light mobile)
  3. Open browser DevTools and run axe.run() in the Console.
  4. Confirm rule landmark-no-duplicate-contentinfo on selector .messages--error.

Expected Behaviour#

Status messages use role="status" (non-error) or role="alert" (errors)

Actual Behaviour#

<div role="contentinfo" aria-labelledby="…"> — conflicts with the page footer landmark

Impact#

blind, low-vision

Suggested Fix#

Change the outer wrapper role based on message type:

{# Before (broken) #} <div role="contentinfo" aria-labelledby="{{ title_ids[type] }}"…>

{# After (fixed) #} {%- set msg_role = (type == 'error') ? 'alert' : 'status' -%} <div role="{{ msg_role }}" aria-labelledby="{{ title_ids[type] }}"…>

Additional References#

Testing Environment#

Tracking IDs#

DRUPAL-A11Y-009—2026-05-06: Homepage has no <h1> heading — screen reader users cannot identify page topic#

Pattern ID: DRU-ADD15A4D Rule: axe-core - page-has-heading-one Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/page-has-heading-one Severity: Medium (axe impact: moderate) WCAG SC: 1.3.1 - Info and Relationships (Level A) Frequency: 2 of 2193 pages (0%) Selector: html XPath: //html Parent Context: N/A

Affected URLs (full list):

Conditions:

HTML Snippet#

<html lang="en" dir="ltr" style="--color--primary-hue:202;--color--primary-saturation:79%;--color--primary-lightness:50" class=" js">

Description#

Fix all of the following: Page must have a level-one heading

Steps to Reproduce#

  1. Go to https://drupal-core.ddev.site/
  2. Use the matching context from Conditions: olivero (dark desktop, dark mobile, light desktop, light mobile)
  3. Open browser DevTools and run axe.run() in the Console.
  4. Confirm rule page-has-heading-one on selector html.

Expected Behaviour#

Every page contains exactly one <h1> that identifies the page

Actual Behaviour#

Olivero front page renders no <h1>; the site name in the header is not an <h1>

Impact#

blind, low-vision

Suggested Fix#

Option A — Make site name an h1 on the front page only:

{# page--front.html.twig #} {% if is_front %} <h1 class="site-name">{{ site_name }}</h1> {% else %} <div class="site-name">{{ site_name }}</div> {% endif %}

Option B — Ensure the promoted front page node has an h1 title rendered.

Additional References#

Testing Environment#

Tracking IDs#

DRUPAL-A11Y-010—2026-05-06: heading-order: Ensure the order of headings is semantically correct#

Pattern ID: DRU-48A2246C Rule: axe-core - heading-order Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/heading-order Severity: Medium (axe impact: moderate) WCAG SC: 1.3.1 - Info and Relationships (Level A) Frequency: 20 of 2193 pages (1%) Selector: #pagination-heading XPath: //*[@id="pagination-heading"] Parent Context: N/A

Affected URLs (full list):

Conditions:

HTML Snippet#

<h4 id="pagination-heading" class="visually-hidden">Pagination</h4>

Description#

Fix any of the following: Heading order invalid

Steps to Reproduce#

  1. Go to https://drupal-core.ddev.site/admin/content
  2. Use the matching context from Conditions: admin (light desktop, light mobile), claro (dark desktop, dark mobile, light desktop, light mobile)
  3. Open browser DevTools and run axe.run() in the Console.
  4. Confirm rule heading-order on selector #pagination-heading.

Expected Behaviour#

Element and interaction meet the mapped WCAG success criterion.

Actual Behaviour#

Fix any of the following: Heading order invalid

Impact#

blind, low-vision

Suggested Fix#

Heading levels must not skip. Audit the page heading hierarchy and adjust template markup.

Additional References#

Testing Environment#

Tracking IDs#

DRUPAL-A11Y-011—2026-05-06: landmark-unique: Ensure landmarks are unique#

Pattern ID: DRU-338C31F8 Rule: axe-core - landmark-unique Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/landmark-unique Severity: Medium (axe impact: moderate) WCAG SC: 1.3.6 - Identify Purpose (Level A) Frequency: 2 of 2193 pages (0%) Selector: .messages--info XPath: //*[contains(@class,"messages--info")] Parent Context: N/A

Affected URLs (full list):

Conditions:

HTML Snippet#

<div role="contentinfo" aria-labelledby="message-info-title" class="messages-list__item messages messages--info">
                            <div class="messages__content">
                          An info message
                      </div>
              </div>

Description#

Fix any of the following: The landmark must have a unique aria-label, aria-labelledby, or title to make landmarks distinguishable

Steps to Reproduce#

  1. Go to https://drupal-core.ddev.site/message
  2. Use the matching context from Conditions: claro (dark desktop, dark mobile, light desktop, light mobile)
  3. Open browser DevTools and run axe.run() in the Console.
  4. Confirm rule landmark-unique on selector .messages--info.

Expected Behaviour#

Element and interaction meet the mapped WCAG success criterion.

Actual Behaviour#

Fix any of the following: The landmark must have a unique aria-label, aria-labelledby, or title to make landmarks distinguishable

Impact#

users with disabilities

Suggested Fix#

See axe documentation.

Additional References#

Testing Environment#

Tracking IDs#

DRUPAL-A11Y-012—2026-05-06: empty-heading: Ensure headings have discernible text#

Pattern ID: DRU-23F4C000 Rule: axe-core - empty-heading Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/empty-heading Severity: Low (axe impact: minor) WCAG SC: unknown - See axe docs (Level ?) Frequency: 28 of 2193 pages (1%) Selector: h3:nth-child(3) XPath: //h3:nth-child(3) Parent Context: N/A

Affected URLs (full list):

Conditions:

HTML Snippet#

<h3></h3>

Description#

Fix any of the following: Element does not have text that is visible to screen readers aria-label attribute does not exist or is empty aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty Element has no title attribute

Steps to Reproduce#

  1. This issue may require opening a dialog/off-canvas panel before running axe.
  2. Go to https://drupal-core.ddev.site/dialog
  3. Use the matching context from Conditions: admin (light desktop, light mobile), claro (dark desktop, dark mobile, light desktop, light mobile)
  4. Open browser DevTools and run axe.run() in the Console.
  5. Confirm rule empty-heading on selector h3:nth-child(3).

Expected Behaviour#

Element and interaction meet the mapped WCAG success criterion.

Actual Behaviour#

Fix any of the following: Element does not have text that is visible to screen readers aria-label attribute does not exist or is empty aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty Element has no title attribute

Impact#

users with disabilities

Suggested Fix#

See axe documentation.

Additional References#

Testing Environment#

Tracking IDs#

DRUPAL-A11Y-013—2026-05-06: empty-table-header: Ensure table headers have discernible text#

Pattern ID: DRU-EDB3860D Rule: axe-core - empty-table-header Axe Rule URL: https://dequeuniversity.com/rules/axe/4.11/empty-table-header Severity: Low (axe impact: minor) WCAG SC: unknown - See axe docs (Level ?) Frequency: 44 of 2193 pages (2%) Selector: th:nth-child(2) XPath: //th:nth-child(2) Parent Context: N/A

Affected URLs (full list):

Conditions:

HTML Snippet#

<th></th>

Description#

Fix any of the following: Element does not have text that is visible to screen readers

Steps to Reproduce#

  1. This issue may require interaction state (typing/dragging/focus) to expose the failing element.
  2. Go to https://drupal-core.ddev.site/autocomplete
  3. Use the matching context from Conditions: claro (dark desktop, dark mobile, light desktop, light mobile)
  4. Open browser DevTools and run axe.run() in the Console.
  5. Confirm rule empty-table-header on selector th:nth-child(2).

Expected Behaviour#

Element and interaction meet the mapped WCAG success criterion.

Actual Behaviour#

Fix any of the following: Element does not have text that is visible to screen readers

Impact#

users with disabilities

Suggested Fix#

See axe documentation.

Additional References#

Testing Environment#

Tracking IDs#


Deduplication & Pattern Grouping#