Skip to content

[Studio UI] Add WAI-ARIA tree roles to element tree - #4056

Open
idaiv wants to merge 10 commits into
2026.xfrom
fix/tree-aria-roles
Open

[Studio UI] Add WAI-ARIA tree roles to element tree#4056
idaiv wants to merge 10 commits into
2026.xfrom
fix/tree-aria-roles

Conversation

@idaiv

@idaiv idaiv commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Tree container: role="tree"
  • Tree nodes: role="treeitem" (replaces role="button")
  • Child lists: role="group"
  • aria-expanded, aria-selected, aria-level on all nodes
  • Fixes WCAG 2.1 4.1.2 (Name, Role, Value)

Test plan

  • Inspect tree container in DevTools — verify role="tree"
  • Inspect a tree node — verify role="treeitem", aria-level, aria-selected
  • Expand a folder — verify aria-expanded="true"
  • Inspect child list wrapper — verify role="group"
  • Test with screen reader — verify tree structure is announced

🤖 Generated with Claude Code

Relates to https://github.com/pimcore/product-management/issues/372

- Container: role="tree"
- Nodes: role="treeitem" (replaces role="button")
- Child lists: role="group"
- aria-expanded on expandable nodes
- aria-selected on all nodes
- aria-level reflecting nesting depth

Screen readers can now identify the tree structure, announce folder
state, selection, and depth. Completes WCAG 2.1 4.1.2 (Name, Role,
Value) for tree components.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings September 1, 2026 14:02
@idaiv idaiv added the Skip Milestone Check Exempts this PR from the mandatory milestone requirement label Sep 1, 2026

Copilot AI 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.

Pull request overview

Verdict: Needs changes. Adds WAI-ARIA tree semantics to the shared element-tree component.

Changes:

  • Adds tree, treeitem, and group roles.
  • Exposes expanded, selected, and hierarchy state through ARIA attributes.

Review contract:

  • Claim: Improve element-tree accessibility for WCAG 4.1.2.
  • Root cause: Only partially addressed; naming, hierarchy, focus, and levels remain incorrect.
  • Call sites: Shared implementation covers all consumers, but labels require consumer updates.
  • Boundary: The shared element-tree component is appropriate.
  • Compatibility: No breaking public API change currently introduced.
  • Tests: No automated accessibility regression coverage was added.
  • Docs/changelog: No public documentation impact identified.
  • Risks: Screen-reader behavior remains unverified and currently exposes invalid semantics.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
element-tree.tsx Adds the tree container role.
list/tree-list.tsx Marks child lists as groups.
node/tree-node.tsx Adds treeitem role and state attributes.
Suppressed comments (2)

assets/js/src/core/components/element-tree/element-tree.tsx:137

  • This behavioral accessibility fix has no automated regression coverage despite existing ElementTree tests and an integration test that renders the real TreeNode. Add assertions for the named tree, parent-owned groups, a tabbable active item, state attributes, valid levels with and without a visible root, and paginated position metadata.
      role="tree"

assets/js/src/core/components/element-tree/list/tree-list.tsx:59

  • These child lists are paginated (total and RenderPager), but their treeitems expose no absolute position or full set size. A screen reader will derive values only from the rendered page, so page-two items can be announced as “1 of N” rather than their real position. Pass absolute aria-posinset and aria-setsize={total} to each rendered child.
        role="group"

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

onKeyDown={ onKeyDown }
ref={ setRef }
role='button'
role='treeitem'
<div
className={ ['tree', styles.tree].join(' ') }
data-testid={ treeTestId }
role="tree"
<div
className='tree-list'
data-testid={ `tree-list-${node.id}` }
role="group"
<Flex
align="center"
aria-expanded={ props.hasChildren === true ? isExpanded : undefined }
aria-level={ level + 1 }
idaiv and others added 9 commits September 1, 2026 14:08
Root node has level={-1}, producing aria-level={0} which is invalid
(WAI-ARIA minimum is 1). Clamp to Math.max(1, level + 1).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Each tree instance (Asset, Document, Data Object) now passes a
translated aria-label to the role="tree" container so screen readers
can distinguish between multiple trees on screen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SonarCloud flags role="group" on a div. Use a ul element instead
which is semantically appropriate for a list of tree items and
satisfies the rule while maintaining the WAI-ARIA tree pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SonarCloud S6819 only accepts <details>, <fieldset>, <optgroup>, or
<address> for the group role — none appropriate for a tree. The
semantic <ul> element inside a role="tree" container is already
understood by assistive technology as a grouping, so the explicit
role attribute is unnecessary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Sep 2, 2026

Copy link
Copy Markdown

@idaiv
idaiv requested a review from vin0401 September 2, 2026 09:27
@idaiv idaiv added this to the 2026.3.0 milestone Sep 2, 2026
@idaiv
idaiv requested a review from martineiber September 2, 2026 10:28
@idaiv idaiv removed the Skip Milestone Check Exempts this PR from the mandatory milestone requirement label Sep 2, 2026
@idaiv
idaiv removed the request for review from martineiber September 2, 2026 10:35
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.

2 participants