Skip to content

Group nested CellTree items and hide the expand images - #22

Merged
gtritchie merged 2 commits into
rstudio/montauk-daisyfrom
bugfix/celltree-group-role-decorative-images
Oct 23, 2026
Merged

gtritchie merged 2 commits into
rstudio/montauk-daisyfrom
bugfix/celltree-group-role-decorative-images

Conversation

@gtritchie

Copy link
Copy Markdown
Member

Axe reports two problems in CellTree, seen in RStudio's Connections pane object browser. Addresses rstudio/rstudio#19244.

  • Nested tree items have no group parent (aria-required-parent). Each CellTreeNodeView element has role="treeitem" and renders its children inside itself, through an animation frame, a content container and a child container, none of which has a role. A nested item's closest ancestor with a role is therefore its parent treeitem. Top-level items pass because the CellTree element has role="tree".
  • The open/closed/loading images have no alt text (image-alt). CellTree.getImageHtml() builds them with AbstractImagePrototype, which emits an <img> with no alt.

Changes

  • CellTreeNodeView.ensureChildContainer() gives the child container role="group" for every node except the root. This produces treeitem > group > treeitem, as in the APG tree pattern. The root's children stay direct descendants of the role="tree" element. The group holds only child items: the empty message and the "show more" link are siblings of the child container in the content container.
  • The imageWrapper template, which wraps all three images, gets aria-hidden="true". The item's aria-expanded already conveys the open/closed state. Leaf items render a separate placeholder <div> with no image and are unchanged.

Testing

New tests in CellTreeTest, both of which failed before the change:

  • testChildContainerRoles: a top-level item's closest ancestor with a role is the tree. Every nested item, down to a leaf, is in a group whose closest ancestor with a role is its parent item.
  • testExpandImagesHiddenFromAssistiveTech: the image wrapper is aria-hidden for an open item, a closed item, an item closed again after being opened, and the loading image.

Results:

  • CellTreeTest and AnimatedCellTreeTest pass in HtmlUnit (48 tests).
  • checkstyle passes, and ant clean dist-dev builds.
  • With RStudio built against this SDK, Axe reports no violations in the Connections pane object browser expanded down to table columns. Before the change, it reported aria-required-parent on every nested item and image-alt on every arrow.

RStudio needs no code change for this: the fix ships when RStudio's GWT_VERSION moves to the release that contains it.

Nested treeitems had no group parent (Axe aria-required-parent), and the
open/closed/loading images had no alt text (Axe image-alt). Mark the image
wrapper aria-hidden and give each non-root node's child container role=group.

Addresses rstudio/rstudio#19244
aria-expanded conveys open/closed but not loading, so the comment no longer
claims it covers the loading image. The image test now asserts the child it
inspects is expandable, since a leaf renders a placeholder without the image.

Addresses rstudio/rstudio#19244

@gtritchie gtritchie left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

No blocking issues. The change fixes both violations it targets, and I found no regressions.

I checked this by building HTML copies of the CellTree DOM before and after the change and running axe-core 4.13 and Chromium's accessibility tree on them. Before the change, axe reports aria-required-parent on nested items and image-alt on the expand images. After the change, it reports neither.

Remaining issues, both of which predate this PR:

  • The top-level "Show more" link is a direct child of role="tree". The root node's anchor is in the root's content container, so the tree element owns it directly. When the link is visible, axe reports aria-required-children ("Element has children which are not allowed: a"). The same link inside a nested item passes. In RStudio this only happens when the object browser has more than 512 top-level items (ObjectBrowser sets that page size), so it is rare. Fixing it means moving the link out of the tree element or giving it a role the tree allows, which is outside the scope of this PR. Worth an issue if anyone reports it.
  • The "No data" message is part of the nested item's accessible name. It is a sibling of the new group inside the treeitem, so Chromium names an open, empty nested item "emptyTable No data". This PR improves naming overall: before it, every item's name included the text of all its descendants (e.g. "schema table1 col1 loadingTable"). The new group stops that everywhere except for this message.

Optional:

  • testChildContainerRoles covers only the first open. The code keeps role="group" after a redraw (loadChildState copies savedChild.childContainer) and after a close followed by a reopen (ensureChildContainer reuses the container), but no test asserts either.

LGTM.

@gtritchie
gtritchie merged commit 405147f into rstudio/montauk-daisy Oct 23, 2026
1 check passed
gtritchie added a commit to rstudio/rstudio that referenced this pull request Oct 23, 2026
…Enter to view a table (#19248)

* Name icon columns and type icons in the connection list

The type and explore columns had empty <th> elements and the type icon had
no alt text. Give both headers visually hidden text and render the type icon
with its connection type as alt, escaping the package-supplied icon source.
Base64ImageCell had no other users, so a Connection-aware cell replaces it.

Addresses #19244

* Open connection tables with Enter in the object browser

The View table icon only responded to clicks, and object icons had no alt
text. Enter on a table item now opens the data viewer, the icon's alt carries
the action label (so it reaches the item's name), object icons use their type
as alt, and icon attributes are escaped.

Addresses #19244

* Cover the object browser tree fixes in the NEWS entry

The CellTree group role and decorative arrow fixes in the GWT fork ship in
the same release, so describe them alongside the RStudio-side changes.

Addresses #19244

* Ignore modified and repeated Enter in the object browser

Ctrl/Cmd/Alt/Shift+Enter and each auto-repeated keydown also opened a data
viewer. Act only on a plain, non-repeated Enter, and have render() and the
key handler share one check for whether an item offers View table.

Addresses #19244

* Test opening a connection table with Enter

Addresses #19244

* Update GWT to 2.13.1-montauk-daisy-4

Picks up the CellTree fix from rstudio/gwt#22: nested tree items get a group
parent and the expand/collapse images are hidden from screen readers.

Addresses #19244

* Share one isRepeating helper for key-repeat checks

ObjectExplorerDataGrid and the connections ObjectBrowserModel each had the
same JSNI check for event.repeat. Move it to KeyboardShortcut, next to
getModifierValue, and use it from both.

Addresses #19244

* Share one helper for visually hidden header text

The Files pane checkbox and icon columns and the two Connections pane icon
columns each built the same visually hidden span by hand. Add
SafeHtmlUtil.visuallyHiddenText and use it at all four sites.

Addresses #19244

* Test Enter key guards in the connection object browser

Add a test that Shift+Enter and a repeated Enter on a table item send no
preview request, counting connection_preview_object requests because a
second preview of an open table reuses its viewer. Keydowns are dispatched
to the item so a refresh of the object tree can't divert them. The plain
Enter test now checks that no viewer is open beforehand, and focuses the
item again if the tree dropped focus before the key landed.

Addresses #19244

* Correct two comments in the Enter key handling and its test

Playwright can send a repeated keydown with a second keyboard.down, so the
test helper's comment no longer claims otherwise. Restore the reason for
ignoring repeated keydowns at the call site, lost when the helper moved.

Addresses #19244
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.

1 participant