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
Copy link

github-actions bot commented Oct 15, 2025

Deployed dev-app for 497fa53 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

Comment on lines +107 to +110
/** 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

detected: feature PR contains a feature commit dev-app preview When applied, previews of the dev-app are deployed to Firebase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants