Skip to content

aria-controls is emitted as an empty string on comboboxes, popovers and date pickers #15400

Description

@bpmore

Bug description

Popup triggers across the CP render aria-controls="" — an empty string — when their popup element has not been created yet.

An empty aria-controls is an invalid attribute value, not a neutral one. Assistive technology is told a controlling relationship exists and then cannot resolve the target.

axe-core reports aria-valid-attr-value (critical, needs-review) on 25 nodes across 9 CP screens.

Examples:

<!-- date picker -->
<button aria-label="Open calendar" aria-haspopup="dialog" aria-expanded="false" aria-controls="">

<!-- combobox trigger -->
<div tabindex="0" aria-haspopup="listbox" aria-expanded="false" aria-controls="">

<!-- generic popover -->
<button data-ui-popover-trigger aria-haspopup="dialog" aria-expanded="false" aria-controls="">

<!-- command palette input -->
<input role="combobox" aria-autocomplete="list" aria-controls="">

Affects Combobox, Popover, the date field, and the command palette. There is a closed issue from the 3.x era on the same theme for SVGs (#2605), so this pattern has come up before.

WCAG 2.1 SC 4.1.2 Name, Role, Value (Level A).

How to reproduce

  1. composer create-project statamic/statamic
  2. Add a date field and a select field to a blueprint, open an entry
  3. In the console:
[...document.querySelectorAll('[aria-controls=""]')].map(e => e.outerHTML.slice(0, 120))

Returns the date-picker trigger and the select trigger, among others.

Suggested fix

Omit the attribute entirely until the popup element exists, rather than binding it to an empty string — i.e. :aria-controls="popupId || undefined" at the points where these are bound.

Since most of these come through reka-ui primitives, the fix may belong in how Statamic configures them (or may be worth an upstream report there).

Related: https://github.com/statamic/cms/blob/v6.31.0/resources/js/components/ui/Combobox/Combobox.vue#L390

Environment

Environment
Laravel Version: 13.30.1
PHP Version: 8.4.23
Composer Version: 2.10.2
Environment: local
Debug Mode: ENABLED
Maintenance Mode: OFF
Timezone: UTC
Locale: en

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: file
Database: sqlite
Logs: stack / single
Mail: log
Queue: sync
Session: file

Storage
public/storage: NOT LINKED

Statamic
Addons: 0
License Key: Not set
Sites: 1
Stache Watcher: Enabled (auto)
Static Caching: Disabled
Version: 6.31.0 PRO

Installation

Fresh statamic/statamic site via CLI

Additional details

Found during a WCAG 2.1 AA audit of a vanilla composer create-project statamic/statamic install with no addons and no custom code. Tested with axe-core 4.x on Chromium 153 at 1440x1000, plus manual keyboard traversal. Source references point at v6.31.0.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions