Skip to content

Conversation

@francinelucca
Copy link
Member

@francinelucca francinelucca commented Jan 28, 2026

Authors: Please fill out this form carefully and completely.

Reviewers: By approving this Pull Request you are approving the code change, as well as its deployment and mitigation plans.
Please read this description carefully. If you feel there is anything unclear or missing, please ask for updates.

What are you trying to accomplish?

Resolve accessibility audit issue where child role is missing

Screenshots

Integration

N/A

List the issues that this change affects.

Closes https://github.com/github/accessibility-audits/issues/14650

Risk Assessment

  • Low risk the change is small, highly observable, and easily rolled back.
  • Medium risk changes that are isolated, reduced in scope or could impact few users. The change will not impact library availability.
  • High risk changes are those that could impact customers and SLOs, low or no test coverage, low observability, or slow to rollback.

What approach did you choose and why?

Consulted a11y on the best fix and decided to add role="treeitem" to the shadow dom node to solve the a11y scan issue, though this may not translate to a real world scenario in this case.

Anything you want to highlight for special attention from reviewers?

N/A

Accessibility

  • Fixes axe scan violation - This change fixes an existing axe scan violation.

Merge checklist

  • Added/updated tests
  • Added/updated documentation
  • Added/updated previews (Lookbook)
  • Tested in Chrome
  • Tested in Firefox
  • Tested in Safari
  • Tested in Edge

Take a look at the What we look for in reviews section of the contributing guidelines for more information on how we review PRs.

@francinelucca francinelucca requested a review from a team as a code owner January 28, 2026 03:45
@francinelucca francinelucca requested review from Copilot and llastflowers and removed request for Copilot January 28, 2026 03:45
@changeset-bot
Copy link

changeset-bot bot commented Jan 28, 2026

⚠️ No Changeset found

Latest commit: 75781e9

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@francinelucca francinelucca added the skip changeset Pull requests that don't change the library output label Jan 28, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR attempts to fix an accessibility audit issue by adding role="treeitem" to the tree-view-include-fragment custom element in the spinner loader component. However, this creates an invalid ARIA tree structure.

Changes:

  • Added role="treeitem" attribute to the tree-view-include-fragment element in spinner_loader.html.erb
Comments suppressed due to low confidence (1)

app/components/primer/alpha/tree_view/spinner_loader.html.erb:5

  • The skeleton_loader.html.erb file does not have role="treeitem" on its tree-view-include-fragment element (line 5), creating an inconsistency with the spinner_loader change. This inconsistency suggests that adding the role to spinner_loader may not be the correct approach. Both loaders should be treated the same way since they serve the same purpose and have the same DOM structure.
<%= render(Primer::BaseComponent.new(tag: :"tree-view-include-fragment", src: @src, loading: :lazy, data: { target: "tree-view-sub-tree-node.subTree tree-view-sub-tree-node.includeFragment", path: @container.path.to_json }, hidden: @container.expanded?, accept: "text/fragment+html", role: "treeitem")) do %>

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

<% end %>

<%= render(Primer::BaseComponent.new(tag: :"tree-view-include-fragment", src: @src, loading: :lazy, data: { target: "tree-view-sub-tree-node.subTree tree-view-sub-tree-node.includeFragment", path: @container.path.to_json }, hidden: @container.expanded?, accept: "text/fragment+html")) do %>
<%= render(Primer::BaseComponent.new(tag: :"tree-view-include-fragment", src: @src, loading: :lazy, data: { target: "tree-view-sub-tree-node.subTree tree-view-sub-tree-node.includeFragment", path: @container.path.to_json }, hidden: @container.expanded?, accept: "text/fragment+html", role: "treeitem")) do %>
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

Adding role="treeitem" to the tree-view-include-fragment element creates an invalid ARIA tree structure. According to the WAI-ARIA specification, a treeitem element cannot contain a group element, but this tree-view-include-fragment wraps a ul[role="group"] (SubTreeContainer).

The actual DOM structure becomes:

li[role="none"]
  └── tree-view-include-fragment[role="treeitem"]  ← Invalid
      └── ul[role="group"]
          └── li[role="none"]
              └── div[role="treeitem"]

The tree-view-include-fragment is a technical implementation detail for lazy loading and should remain role-less (allowing it to be transparent in the accessibility tree). The actual treeitems are the div[role="treeitem"] elements inside the ul[role="group"] that this fragment contains.

Note that skeleton_loader.html.erb does not have this role attribute, creating an inconsistency. The correct fix depends on what the actual accessibility issue is. If the concern is that the loading indicator needs to be announced, the role should be on the inner Node element (which already has role="treeitem" from Node.rb line 108), not on the outer include-fragment wrapper.

Suggested change
<%= render(Primer::BaseComponent.new(tag: :"tree-view-include-fragment", src: @src, loading: :lazy, data: { target: "tree-view-sub-tree-node.subTree tree-view-sub-tree-node.includeFragment", path: @container.path.to_json }, hidden: @container.expanded?, accept: "text/fragment+html", role: "treeitem")) do %>
<%= render(Primer::BaseComponent.new(tag: :"tree-view-include-fragment", src: @src, loading: :lazy, data: { target: "tree-view-sub-tree-node.subTree tree-view-sub-tree-node.includeFragment", path: @container.path.to_json }, hidden: @container.expanded?, accept: "text/fragment+html")) do %>

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip changeset Pull requests that don't change the library output

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants