Skip to content

Conversation

@ok7sai
Copy link
Member

@ok7sai ok7sai commented Oct 15, 2025

Things are (mostly) done

  • UI patterns implemented based off https://www.w3.org/WAI/ARIA/apg/patterns/grid/
  • ngGrid, ngGridRow, ngGridCell, ngGridCellWidget directives.
  • keyboard navigation, keyboard selection, pointer selection(single click w/wo modifier and dragging), supporting interactable widgets contained in a cell.
  • A grid based pill list example and a general example to showcase navigation and selection.

Next up

  • Add an example of data table with editable fields.
  • Consider adding other selection strategies (e.g. multi range selection? whether to clear selection when moving cell focus like Google Sheets, etc)
  • Consider adding scrolling keyboard shortcuts PageUp/PageDown. (configurable scroll up/down rows? or leave to devs to trigger data table pagination?)
  • Enable TreeGrid mode.
  • Thorough tests.

@ok7sai ok7sai requested a review from wagnermaciel October 15, 2025 23:36
@ok7sai ok7sai requested review from a team as code owners October 15, 2025 23:36
@ok7sai ok7sai requested review from tjshiu and removed request for a team October 15, 2025 23:36
@ok7sai ok7sai added the dev-app preview When applied, previews of the dev-app are deployed to Firebase label Oct 15, 2025
@angular-robot angular-robot bot added the detected: feature PR contains a feature commit label Oct 15, 2025
@github-actions
Copy link

github-actions bot commented Oct 15, 2025

Deployed dev-app for dc071d7 to: https://ng-dev-previews-comp--pr-angular-components-32092-dev-d6byq9uh.web.app

Note: As new commits are pushed to this pull request, this link is updated after the preview is rebuilt.

readonly element = computed(() => this._elementRef.nativeElement);

/** Whether grid navigation should be paused, usually because this widget has focus. */
readonly pauseGridNavigation = model<boolean>(false);
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like something that shouldn't be exposed for developers to control

/** Gets the `tabindex` for the widget within the cell. */
widgetTabIndex(): -1 | 0 {
return this._tabIndex();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

What happens if there are multiple widgets inside of the cell?

Copy link

@OmerGronich OmerGronich Oct 17, 2025

Choose a reason for hiding this comment

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

Really appreciate this work, super excited to see @angular/aria expanding to cover the grid pattern.

Just wanted to mention a use case where multiple widgets inside of a cell might make sense.
There's React Aria's "grid-list" pattern where each row is a single cell with multiple interactive elements inside. Think a file list where each item has separate buttons for open, selection, download, delete, etc.

It’d be great if this use case could be supported.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the ideas! Use case of multiple widgets is certainly going to be supported. The widget concept here is more of a container that allows widget/widgets inside a cell to take over the keyboard control from the grid. E.g. allowing a list of widgets or even another grid of widgets in a cell. We are still sorting out the widget stories aim to provide out of box experience for canonical use cases and meanwhile making the API flexible enough for complex use cases.

/** The main class that orchestrates the grid behaviors. */
export class Grid<T extends GridCell> {
/** The underlying data structure for the grid. */
readonly data: GridData<T>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to store and track this data in the cells themselves?

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's not optimize this right now. If this becomes an issue we can refactor this internally affecting the public api.

Copy link
Member

@josephperrott josephperrott left a comment

Choose a reason for hiding this comment

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

LGTM

Reviewed for infra

{{item.label}}
</div>
<div ngGridCell class="example-pill-action example-stateful example-grid-cell">
<button ngGridCellWidget class="example-pill-button" (click)="removeItem(i)">
Copy link

@OmerGronich OmerGronich Oct 17, 2025

Choose a reason for hiding this comment

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

Noticed something in the “Pill List” example: when removing a pill, focus seems to leave the grid entirely. After that, keyboard navigation no longer works until I tab back into the grid.

In the WAI-ARIA grid example, focus stays within the grid, after removing a pill it moves to the next one (or the previous if it was the last). Angular Material chips input extend this pattern: when the last chip is removed, focus shifts to the input.

In addition, those implementations treat the input as a separate tab stop from the grid, which allows moving between the pill list and input with a single Tab key press, a pattern that works well for this type of list.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you so much for testing out the demo! Yes I am aware of the losing focus issue and am working on the restoring focus logic when a deletion happen. The input is how I tested out the cell widget behavior and I will switch to something similar to the APG example once I have another example demonstrating the widget usage.

@angular-robot angular-robot bot added the area: build & ci Related the build and CI infrastructure of the project label Oct 20, 2025
@ok7sai ok7sai added action: merge The PR is ready for merge by the caretaker target: minor This PR is targeted for the next minor release labels Oct 21, 2025
@wagnermaciel
Copy link
Contributor

Something to look into after this lands:
It looks like there is some drifting going on where arrowing in one direction will move you out of the row/col you are navigating through. E.g. if you go to the 3rd to last cell in the first row and start arrowing down, you end up traversing all the way to the middle of the grid

@ok7sai ok7sai removed the request for review from tjshiu October 21, 2025 17:34
@ok7sai ok7sai merged commit a821a3e into angular:main Oct 21, 2025
28 checks passed
@ok7sai ok7sai deleted the ng-aria-grid branch October 21, 2025 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action: merge The PR is ready for merge by the caretaker area: build & ci Related the build and CI infrastructure of the project detected: feature PR contains a feature commit dev-app preview When applied, previews of the dev-app are deployed to Firebase target: minor This PR is targeted for the next minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants