Skip to content

feat(standards/ariaAttrs): add caseInsensitive property for attributes - #5224

Merged
WilcoFiers merged 10 commits into
developfrom
get-aria-value-changes
Aug 5, 2026
Merged

feat(standards/ariaAttrs): add caseInsensitive property for attributes#5224
WilcoFiers merged 10 commits into
developfrom
get-aria-value-changes

Conversation

@straker

@straker straker commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Add the caseInsensitive property to the aria attrs standard. This is used to automatically lowercase the value for commons.aria.getAriaValue instead of having to manually pass { lowercase: true } every time you wanted to access one of the attributes. This updates aria-expanded, aria-hidden, aria-haspopup, aria-selected, aria-invalid, aria-disabled, and ara-live to be case insensitive (which we have tested in prior prs).

Additionally, as a chore style change this also updates getAriaValue to not return null anymore but instead { value: null, source: null } so that we don't have to conditionally access the value property of the return.

@straker
straker requested a review from a team as a code owner July 20, 2026 21:10
@straker straker changed the title feat(standards/aria): add caseInsensitive property for attributes feat(standards/ariaAttrs): add caseInsensitive property for attributes Jul 20, 2026

@WilcoFiers WilcoFiers left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tackling this — the caseInsensitive flag is a nice cleanup. A few things to address before merge, mostly around consistency and finishing the replacement.

Important

1. Leftover { lowercase: true } for the now-caseInsensitive attrs. Some call sites weren't updated:

These are redundant now and undercut the stated goal of the PR. A repo-wide grep for lowercase: true would confirm none of the four flagged attrs still pass it.

2. Doc/test typo caseInsenstive. doc/standards-object.md:54 and the test name at test/commons/aria/get-aria-value.js:128 spell it caseInsenstive — the actual property is caseInsensitive, so the docs describe a property that doesn't exist.

3. aria-selected is treated case-insensitively but not flagged in the standard. aria-valid-attr-value-evaluate.js:57 lowercases aria-selected via { lowercase: true }, but aria-selected in the standard is not marked caseInsensitive. So axe already treats it case-insensitively at this one call site while the standard says it's case-sensitive. WAI-ARIA treats enumerated token values as case-insensitive generally, so as part of this work we should test the remaining token props to confirm whether they're actually still case-sensitive, and mark them accordingly (or intentionally leave them and document why — see below). At minimum aria-selected should be reconciled so behavior doesn't depend on the call site.

Suggestions

4. Document why some token props are left case-sensitive. Since the spec treats enumerated token values as case-insensitive but this PR flags only four attributes, add a note (in lib/standards/aria-attrs.js and/or the doc) explaining why the remaining token attributes are intentionally left case-sensitive in Axe. Where we don't have test data yet, we'll need to run the tests.

5. Redundant optional chaining. Now that getAriaValue always returns an object, remaining ?.value calls (e.g. aria-valid-attr-value-evaluate.js:45) are dead defensiveness and mix styles within the file. Low priority.

Comment thread test/commons/text/form-control-value.js
WilcoFiers
WilcoFiers previously approved these changes Jul 29, 2026

@WilcoFiers WilcoFiers left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can live with leaving testing of those lesser used props for another time, but in that case please open an issue.

Comment thread lib/standards/aria-attrs.js
Comment thread lib/standards/aria-attrs.js
Comment thread lib/standards/aria-attrs.js
Comment thread lib/standards/aria-attrs.js
Comment thread lib/standards/aria-attrs.js
Comment thread lib/standards/aria-attrs.js
Comment thread lib/standards/aria-attrs.js

@chutchins25 chutchins25 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work — 58cb8a08 is a good deal more than was asked for. 20 of the 23 token/boolean attrs now carry an explicit caseInsensitive value, and the per-AT rationale comments on the nine false ones are genuinely useful to have in the standard.

A few things I checked that seem worth recording:

  • Every removed { lowercase: true } maps to an attribute now marked caseInsensitive: true — all 8 call sites (aria-invalid, aria-hidden ×3, aria-expanded ×3, aria-haspopup, aria-selected, aria-live, aria-disabled). No silent loss of lowercasing.
  • The getAriaValue return-shape change isn't a breaking change: lib/commons/aria/get-aria-value.js is absent from v4.11.4, v4.12.0 and v4.12.1, and getAriaValue appears nowhere in doc/. It's never shipped, so there's no public contract to break.
  • Items 1, 3 and 5 from the first round all check out on this head — zero lowercase: true left in lib/ (the three remaining hits are tests of the option itself on aria-label), aria-selected is now flagged in the standard, and zero ?.value left in any changed lib file.

One process thing: @WilcoFiers asked for an issue if the lesser-used props were left untested, and I couldn't find one. #4618 is the only open case-sensitivity ticket and it's a broad 2024 "go over the code base" item that doesn't name these attributes, and there's no Closes line on this PR. Worth filing before merge so that condition is actually met.

Plus a question inline about the aria-selected test that lost its uppercase case, and a note on aria-attrs.js about the three unresolved attrs.

Comment thread lib/standards/aria-attrs.js
@@ -357,7 +357,6 @@ describe('text.formControlValue', () => {
const target = queryFixture(html`
<div id="target" role="listbox">
<div role="option" aria-selected="false">foo</div>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropping the aria-selected="TRUE" case from this test makes sense — with aria-selected now caseInsensitive: true it resolves to 'true', so "bar" becomes selected and this assertion would flip from '' to 'bar'.

The part I'd flag is that nothing replaced it. As far as I can tell it was the only test touching uppercase aria-selected, so the change to ariaListboxValue (form-control-value.js:150-154) now has no coverage at this call site. Your note that you'd tested it is on the thread attached to the deleted line, so the verification exists but isn't captured in code. Worth adding the positive counterpart?

it('returns the option when aria-selected is not lowercase', () => {
  const target = queryFixture(html`
    <div id="target" role="listbox">
      <div role="option" aria-selected="false">foo</div>
      <div role="option" aria-selected="TRUE">bar</div>
    </div>
  `);
  assert.equal(ariaListboxValue(target), 'bar');
});

(Plain block rather than a suggestion since it needs to land after this test's closing brace.)

@WilcoFiers
WilcoFiers merged commit bcd791c into develop Aug 5, 2026
41 of 42 checks passed
@WilcoFiers
WilcoFiers deleted the get-aria-value-changes branch August 5, 2026 15:51
WilcoFiers added a commit that referenced this pull request Aug 5, 2026
All notable changes to this project will be documented in this file. See
[commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version)
for commit guidelines.

##
[4.13.0](v4.12.1...v4.13.0)
(2026-08-05)

### Features

- **aria-actions:** add aria-actions to allowed ARIA attributes
([#5200](#5200))
([029655d](029655d)),
closes [#4584](#4584)
[#5199](#5199), references
[#5215](#5215)
[#5215](#5215)
- **aria-allowed-attr:** flag deprecated ARIA attributes as needs-review
([#5246](#5246))
([518f3cc](518f3cc)),
closes [#3341](#3341)
- **aria-prohibited-attr:** allow many elements to be named and disallow
label and body from being named
([#5259](#5259))
([d8b1ea5](d8b1ea5))
- **aria-roles:** add sectionheader and sectionfooter roles
([#5238](#5238))
([c36c109](c36c109)),
closes [#4734](#4734),
references [#4734](#4734)
- **aria/get-aria-value:** new function to get aria values of a node
([#5109](#5109))
([a7d8f3e](a7d8f3e)),
references [#5042](#5042)
- **aria/has-attr-value:** new function to check if node has aria value
([#5136](#5136))
([61f2624](61f2624)),
references [#5109](#5109)
- **aria:** support role=image as equivalent to role=img
([#5248](#5248))
([5aa8aaf](5aa8aaf)),
closes [#4656](#4656),
references [#5272](#5272)
- **checks/aria:** support ARIA element internals properties
([#5172](#5172))
([9b7f754](9b7f754))
- **checks/label:** support ARIA element internals properties
([#5170](#5170))
([21c5f8b](21c5f8b))
- **checks/navigation:** support ARIA element internals properties
([#5167](#5167))
([2c3a98f](2c3a98f))
- **commons/aria:** support ARIA element internals properties
([#5171](#5171))
([31f09e7](31f09e7))
- **commons/dom:** support ARIA element internals properties
([#5163](#5163))
([f0a12cf](f0a12cf))
- **commons/forms:** support ARIA element internals properties
([#5165](#5165))
([27a4686](27a4686))
- **commons/matches/fromPrimative:** deprecate in favor of correct
spelling ([#5270](#5270))
([31cfb2e](31cfb2e))
- **commons/text:** support ARIA element internals properties
([#5169](#5169))
([e841a33](e841a33))
- **commons/text:** support form-associated labels via element internals
([#5182](#5182))
([57cfe0a](57cfe0a)),
closes [#5045](#5045),
references [#5170](#5170)
[#5039](#5039)
[#5151](#5151)
[#5039](#5039)
- **dom/getResolvedRefs:** new function to get the resolved virtual
nodes of idrefs
([#5151](#5151))
([489cdea](489cdea)),
references [#5109](#5109)
- **element-internals:** enable ElementInternals by default
([#5284](#5284))
([2740d42](2740d42)),
closes [#5277](#5277)
- **i18n:** Add Swedish locale
([#5190](#5190))
([dcd13f2](dcd13f2)),
references [#5189](#5189)
- **matches:** add inSectioningContent, hasChild, and
isSummaryForDetails matches
([#5262](#5262))
([c47cdcd](c47cdcd))
- **rules:** support ARIA element internals properties
([#5168](#5168))
([065baf7](065baf7))
- **standards/ariaAttrs:** add caseInsensitive property for attributes
([#5224](#5224))
([bcd791c](bcd791c))

### Bug Fixes

- **aria-allowed-role:** allow roles on a non-details summary
([#5242](#5242))
([3bd9875](3bd9875)),
closes [#3911](#3911),
references [#3443](#3443)
[#3911](#3911)
- **aria-allowed-role:** restrict figure roles with child figcaption
([#5240](#5240))
([178a635](178a635)),
closes [#3443](#3443)
- **aria-prohibited-attr:** visible aria-labelledby requires review only
([#5285](#5285))
([fd6fa9f](fd6fa9f))
- **axe.d.ts:** make enabled property of RuleMetadata optional
([#5129](#5129))
([90fce18](90fce18))
- **color-contrast:** fix various stacking context bugs
([#5214](#5214))
([d5e5b04](d5e5b04)),
references [#8](#8)
[#5213](#5213)
- **gather-internals:** handle non-HTMLElement nodes
([#5161](#5161))
([06e84c3](06e84c3))
- **get-selector:** escape control characters in attribute selectors
([#5273](#5273))
([4b60ac5](4b60ac5)),
closes [#5204](#5204)
[#5204](#5204)
- **image-alt:** allow whitespace alt on presentational images
([#5218](#5218))
([c5dd0ef](c5dd0ef)),
closes [#5216](#5216)
- **landmark-unique:** exclude section/form with non-landmark roles from
landmark match
([#5085](#5085))
([c5fd013](c5fd013)),
closes [#4722](#4722)
[#5064](#5064)
- name the image role in role-img-alt and svg-img-alt metadata
([#5279](#5279))
([995a269](995a269)),
closes [#5272](#5272),
references [#5248](#5248)
[#5248](#5248)
- **standards:** update aria-errormessage and aria-details to be idrefs
([#5157](#5157))
([fb94f8a](fb94f8a))

This PR was opened by a robot 🤖 🎉
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants