Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessible name calculation should not allow fallback from empty <label>s #4620

Open
1 task done
dbjorge opened this issue Oct 22, 2024 · 0 comments
Open
1 task done
Labels
false negative rules Issue or false result from an axe-core rule

Comments

@dbjorge
Copy link
Contributor

dbjorge commented Oct 22, 2024

Product

axe-core

Product Version

4.10.1

Latest Version

  • I have tested the issue with the latest version of the product

Issue Description

The following checks:

  • non-empty-placeholder (used by the label rule)
  • non-empty-value (used by the input-button-name rule)
  • non-empty-title (used by many *-name rules)
  • button-has-visible-text (used by the button-name rule)

...currently work by just checking the specific attribute/content they're associated with, ignoring other context. However, it turns out that in some browsers (notably Chrome), the presence of an empty <label> (either implicitly or explicitly linked) will result in these cases being ignored during accessible name calculations. We think this is likely an HTML-AAM violation on Chrome and Safari's parts, but for accessibility-supported purposes, axe-core should respect the least-functional of the fallback behaviors (Chrome's).

I verified that this applies to at least the label, button-name, and input-button-name rules, but note that this probably applies to the other rules that rely on non-empty-title as well (we'll need to add integration tests of that as part of this update)

Note that we'll also want to make corresponding updates to axe's own accessible name calculations, in addition to those specific checks.

Standard interpretation

HTML-AAM §4.1.1 step 3 is consistent with this for title attributes:

  1. If the control has an aria-label or an aria-labelledby attribute the accessible name is to be calculated using the algorithm defined in Accessible Name and Description: Computation and API Mappings.
  2. Otherwise use the associated label element or elements accessible name(s) - if more than one label is associated; concatenate by DOM order, delimited by spaces.
  3. If the accessible name is still empty, then: use the control's title attribute.
  4. Otherwise use the control's placeholder value.
  5. If none of the above yield a usable text string there is no accessible name.

The word "Otherwise" in step 4 is a bit ambiguous, but based on the PR introducing the language, I think it was probably meant to be read similarly to step 3 (ie, as if "Otherwise" were replaced with "If the accessible name is still empty, then: "), which would also be consistent with the current label behavior.

Accessibility Supported status

Unfortunately, the accessibility supported state isn't really consistent with any reasonable interpretation of the standard. Firefox falls back like the label rule expects, but Chrome never fallsand Safari will treat elements with empty <label>s as having empty accessible names in most cases, even if a non-empty placeholder or title is present:

<!-- new label integration tests -->
<label for="fail15"></label>
<input id="fail15" type="text" placeholder="placeholder value">

<label><input id="fail16" type="text" placeholder="placeholder value"></label>

<label for="fail17"></label>
<input id="fail17" type="text" title="title value">

<label><input id="fail18" type="text" title="title value"></label>

<!-- new button-name integration tests -->
<label for="fail5"></label>
<button id="fail5" title="title value"></button>

<label><button id="fail6" title="title value"></button></label>

<label for="fail7"></label>
<button id="fail7">content</button>

<label><button id="fail8">content</button></label>

<!-- new input-button-name integration tests -->
<label for="fail11"></label>
<input type="button" id="fail11" value="value attr" />

<label><input type="button" id="fail12" value="value attr" /></label>

The accessible names as reported by browsers are:

Case Chrome 130.0.6723.59 Safari 17.6 (19618.3.11.11.5) Firefox 131.0.3
label fail15 "" "" "placeholder value"
label fail16 "" "placeholder value" "placeholder value"
label fail17 "" "" "title value"
label fail18 "" "" "title value"
button-name fail5 "" "" "title value"
button-name fail6 "" "" "title value"
button-name fail7 "" "" "content"
button-name fail8 "" "content" "content"
input-button-name fail5 "" "" "value attr"
input-button-name fail6 "" "value attr" "value attr"

Expectation

All 10 of the cases above should be violations, since at least one of our accessibility-supported browser combos report empty accessible names for them.

Actual

All 10 of those cases pass

How to Reproduce

See above

Additional context

Original report

See this axe-community slack thread. Thanks @pattonwebz for the original report!

aria-label/aria-labelledby out-of-scope

Note that the lack of fallback here only applies to empty <label> elements! All 3 browsers do fall back from empty aria-label and aria-labelledby cases to titles and placeholders:

<!-- new label integration tests -->
<div id="empty-label"></div>
<input id="pass18" type="text" aria-label="" placeholder="placeholder value">
<input id="pass19" type="text" aria-labelledby="empty-label" placeholder="placeholder value">
<input id="pass20" type="text" aria-label="" title="title value">
<input id="pass21" type="text" aria-labelledby="empty-label" title="title value">
Case Chrome Safari Firefox
label pass18 "placeholder value" "placeholder value" "placeholder value"
label pass19 "placeholder value" "placeholder value" "placeholder value"
label pass20 "title value" "title value" "title value"
label pass21 "title value" "title value" "title value"
Suggested check fixes

At the check level, I think the simplest fix would probably be to update the 4 checks in question to return false if an implicit or explicit label is present, which a custom check message explaining why they're inapplicable.

If we write the integration tests and find that actually there are some cases where the current behavior with non-empty-title is correct, we could instead consider something similar to the exiting "none": ["hidden-explicit-label"] check config in the label rule, adding a special check that just reports on this specific incompatibility. I think that'd probably result in worse check messaging in the unaffected cases, though; I think it'd be better to avoid adding more verbosity to those rules' remediation messages, they're already a bit dense.

Suggested accessible name calculation fixes

I think for this it'd be cleaner to do it a bit differently from the checks and closer to how it seems like Chrome is operating in practice. Currently, accessible-text-virtual.js and native-text-alternative.js both contain reduce calls that iterate over the name calculation steps and treat cases where a step returns '' as meaning "fall back to the next step". Since it seems like the chrome behavior really boils down to "if the name from <label> is empty, treat it as a special halting empty name", I'd lean towards updating those core loops to support steps indicating a similar concept, maybe something like a Symbol('halting-empty-string') that is understood to exit-fast from the steps, and update the labelText naming method implementation to return that if it sees a present-but-empty case.

Other updates

We'll want to audit everywhere else our label, labelVirtual, and labelText functions are called to double check if there are any other cases repeating name calculation logic that need similar updates

@dbjorge dbjorge added ungroomed Ticket needs a maintainer to prioritize and label rules Issue or false result from an axe-core rule false negative and removed ungroomed Ticket needs a maintainer to prioritize and label labels Oct 22, 2024
@dbjorge dbjorge changed the title Accessible name calculation should not allow fallback from empty labels to placeholder/title/value attributes Accessible name calculation should not allow fallback from empty <label>s Oct 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
false negative rules Issue or false result from an axe-core rule
Projects
None yet
Development

No branches or pull requests

1 participant