Skip to content

feat(matches): add inSectioningContent, hasChild, and isSummaryForDetails matches - #5262

Merged
straker merged 18 commits into
developfrom
matches
Aug 3, 2026
Merged

feat(matches): add inSectioningContent, hasChild, and isSummaryForDetails matches#5262
straker merged 18 commits into
developfrom
matches

Conversation

@straker

@straker straker commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

This should allow us to handle the variant matching in htmlElms needed for header, footer, figure, and summary.

{
  header: {
    variant: {
      sectioned: {
        matches: {
          inSectioningContent: true
        }
      }
    } 
  },

  figure: {
    variant: {
      figcaption: {
        matches: {
          hasChild: 'figcaption'
        }
      }
    } 
  },

  summary: {
    variant: {
      details: {
        matches: {
          isSummaryForDetails: true
        }
      }
    } 
  }
}

Comment thread lib/commons/matches/first-of-type.js Outdated
Comment thread lib/commons/matches/has-ancestor.js Outdated
Comment thread lib/commons/matches/has-descendant.js Outdated
@straker straker changed the title feat(matches): add hasAncestor, hasDescendant, and firstOfType matches feat(matches): add hasAncestor, hasDescendant, and summaryForDetails matches Jul 29, 2026
@straker straker changed the title feat(matches): add hasAncestor, hasDescendant, and summaryForDetails matches feat(matches): add inSectioningContent, hasDescendant, and summaryForDetails matches Jul 30, 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.

Nice direction overall — expressing the header/footer, figure, and summary variants as matchers is the right shape, and hand-rolling the role lookup instead of calling getRole is the correct call given #5263.

Two correctness issues need resolving before this can be the foundation for the htmlElms work, plus a semantics question on the ancestor walk.

Critical

  • inSectioningContent applies conflict resolution unconditionally, so any focusable or globally-labelled element loses its explicit role. One test currently asserts the incorrect result.

Important

  • inSectioningContent and isSummaryForDetails ignore the matcher argument, so { inSectioningContent: false } can't be expressed — which is exactly what the header/footer banner variant needs.
  • hasDescendant counts a nested figure's caption for the outer figure.
  • The ancestor walk is self-inclusive, so sectioning elements match themselves.

Suggestions

  • JSDoc corrections, test independence from the standards data, and expanding the loop-avoidance comment to name #5263 as its removal condition.

Details inline.

Comment thread lib/commons/matches/in-sectioning-content.js Outdated
Comment thread lib/commons/matches/in-sectioning-content.js
Comment thread lib/commons/matches/in-sectioning-content.js Outdated
Comment thread lib/commons/matches/in-sectioning-content.js Outdated
Comment thread lib/commons/matches/is-summary-for-details.js Outdated
Comment thread lib/commons/matches/has-descendant.js Outdated
Comment thread test/commons/matches/in-sectioning-content.js Outdated
@straker straker changed the title feat(matches): add inSectioningContent, hasDescendant, and summaryForDetails matches feat(matches): add inSectioningContent, hasChild, and summaryForDetails matches Jul 30, 2026
@straker straker changed the title feat(matches): add inSectioningContent, hasChild, and summaryForDetails matches feat(matches): add inSectioningContent, hasChild, and isSummaryForDetails matches Jul 30, 2026

@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 — replacing hasAncestor/hasDescendant/firstOfType with these three
matchers is the right shape, and switching inSectioningContent to getRole is the
correct fix for the conflict-resolution bug from the last round (it gets
<main role="none" aria-label> and the element-internals case right, where the
hand-rolled version didn't). Confirmed resolved on ef121b9e: the self-inclusive
walk, the JSDoc @params, the tests deriving their expectations from the standards
data, and the nested-figcaption problem (hasChild being direct-children-only
sidesteps it entirely).

Four things, two of them concrete bugs:

  1. isSummaryForDetails got the fromPrimative fix on its return path but not its
    early return, so the negated form still reports the wrong answer.
  2. hasChild throws a TypeError on a SerialVirtualNode with no children — the
    virtual-rule path this is being built for.
  3. inSectioningContent's disconnected-tree guard is unreachable for a node whose own
    parent is undefined, so it throws at depth ≥ 2 but silently returns false at
    depth 1. Which answer is intended?
  4. Dropping the hand-rolled role lookup reopens the <section> accname re-entrancy
    path, and the comment that recorded why it was hand-rolled went with it. Nothing
    misbehaves today, but it makes #5263 a prerequisite for the htmlElms work rather
    than a cleanup — worth writing that down somewhere.

Details inline.

Comment thread lib/commons/matches/is-summary-for-details.js
Comment thread lib/commons/matches/has-child.js
Comment thread lib/commons/matches/in-sectioning-content.js Outdated
Comment thread lib/commons/matches/in-sectioning-content.js Outdated
Comment thread lib/commons/matches/has-child.js
Comment thread lib/commons/matches/has-child.js Outdated
Comment thread lib/commons/matches/is-summary-for-details.js Outdated
Comment thread lib/standards/html-elms.js Outdated
Comment thread lib/standards/html-elms.js
@straker
straker merged commit c47cdcd into develop Aug 3, 2026
23 checks passed
@straker
straker deleted the matches branch August 3, 2026 16:37
chutchins25 added a commit that referenced this pull request Aug 3, 2026
…variant

Replace the inline condition function in the figure figcaption variant with
the serializable hasChild: 'figcaption' matcher from #5262 so the standards
object stays function-free. Behavior is unchanged.
chutchins25 added a commit that referenced this pull request Aug 3, 2026
…the summary variant

Replace the inline condition function in the summary variant with the
serializable isSummaryForDetails matcher from #5262 so the standards
object stays function-free. The matcher intentionally throws for a
disconnected (parentless) node, so the virtual-rule test now gives the
summary a non-details parent.
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