Skip to content

Comments

Make rows focusable, remove focus sink#3963

Merged
nstepien merged 8 commits intomainfrom
nosink
Feb 20, 2026
Merged

Make rows focusable, remove focus sink#3963
nstepien merged 8 commits intomainfrom
nosink

Conversation

@nstepien
Copy link
Collaborator

@nstepien nstepien commented Feb 19, 2026

Fixes #3957

Only header rows are not focusable, because it gets tricky with column grouping.
But maybe we could enable column grouping in TreeDataGrid now 🤔

@nstepien nstepien self-assigned this Feb 19, 2026

export async function scrollGrid(options: ScrollToOptions) {
page.getGrid().element().scrollTo(options);
page.getGrid().element().scroll(options);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@codecov-commenter
Copy link

codecov-commenter commented Feb 19, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.54%. Comparing base (089afb9) to head (ca2dcaf).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3963      +/-   ##
==========================================
- Coverage   97.61%   97.54%   -0.08%     
==========================================
  Files          36       36              
  Lines        1470     1467       -3     
  Branches      480      472       -8     
==========================================
- Hits         1435     1431       -4     
- Misses         35       36       +1     
Files with missing lines Coverage Δ
src/DataGrid.tsx 98.98% <100.00%> (-0.02%) ⬇️
src/GroupCell.tsx 100.00% <100.00%> (ø)
src/GroupRow.tsx 100.00% <100.00%> (ø)
src/HeaderCell.tsx 95.94% <100.00%> (-1.46%) ⬇️
src/HeaderRow.tsx 100.00% <ø> (ø)
src/Row.tsx 100.00% <100.00%> (ø)
src/SummaryCell.tsx 100.00% <ø> (ø)
src/SummaryRow.tsx 100.00% <100.00%> (ø)
src/TreeDataGrid.tsx 94.38% <ø> (ø)
src/utils/styleUtils.ts 100.00% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.


export const row = css`
@layer rdg.Row {
display: contents;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Rows are now part of the layout.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is great!

await expect.element(headerCells).toHaveLength(0);
await expect.element(cells).toHaveLength(0);
await expect.element(rows).toHaveLength(0);
await expect.element(rows).toHaveLength(34);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I guess it ignored rows previously because they were empty and not part of the layout?

@nstepien nstepien marked this pull request as ready for review February 19, 2026 23:02

export const row = css`
@layer rdg.Row {
display: contents;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is great!

if (!(target instanceof Element)) return;

const isCellEvent = target.closest('.rdg-cell') !== null;
const isRowEvent = isTreeGrid && target.role === 'row';
Copy link
Collaborator

Choose a reason for hiding this comment

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

Wonder if we can/should move the focus logic to the TreeGrid component. I will check

}

&:focus {
outline: none;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we not set outline on the focused row?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I set border instead as it's 1 line (no negative offset)
Had to remove the default focus style with outline: none.
The border is always set when the row has the [tabindex='0'] attribute, so this is the same behavior as before: if the position is set on a row/cell, we highlight it, regardless of actual :focus

Would you rather we use outline instead of border?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I was wondering if pseudo elements are needed to set row focus styles. Can we not used the same strategy as cell and set outline? or border? I am okay with either

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Unfortunately it doesn't work because the cells render above the outline 🤷‍♂️
I'll add a comment

Comment on lines +30 to +37
& > .${cellFrozen}:first-child::before {
content: '';
display: inline-block;
position: absolute;
inset-block: 0;
inset-inline-start: 0;
border-inline-start: var(--rdg-selection-width) solid var(--rdg-selection-color);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we need this?

Copy link
Collaborator Author

@nstepien nstepien Feb 20, 2026

Choose a reason for hiding this comment

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

To keep the blue border on the first frozen cell, otherwise when we scroll horizontally the border at the start of the row will disappear.

This was implemented as rowSelectedWithFrozenCell before (same file)

@layer rdg.Row {
display: contents;
display: grid;
grid-column: 1/-1;
Copy link
Collaborator

Choose a reason for hiding this comment

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

by default grid-row is 1?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We set gridRowStart in JS, so we don't rely on grid-row defaults.
By default, if you don't specify grid-row I believe it just finds the first available grid row.

[fun fact] Also because we set
grid-template: subgrid / subgrid
-> grid-template-rows: subgrid;
-> the row inherits the row config from the parent grid
-> the row only spans 1 grid row, so it lays out its children in this grid row
-> cells have only 1 grid row to render into

When I tried grid-template-columns: subgrid; without grid-template-rows, there were rendering bugs sometimes:
Chrome:
image
Firefox:
image

If I try to set the same row size instead of subgrid, again focused rows bug out:
image
image

To fix this I'd have to set grid-row on all cells / focus highlight so they don't generate new grid tracks.
subgrid is easier.

amanmahajan7
amanmahajan7 previously approved these changes Feb 20, 2026
Copy link
Collaborator

@amanmahajan7 amanmahajan7 left a comment

Choose a reason for hiding this comment

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

👏


// collpase parent group
await userEvent.keyboard('{arrowdown}{arrowdown}{arrowleft}');
await userEvent.keyboard('{arrowdown}{arrowdown}{arrowleft}{arrowleft}');
Copy link
Collaborator

@amanmahajan7 amanmahajan7 Feb 20, 2026

Choose a reason for hiding this comment

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

why do we need extra {arrowleft}?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

to change selection to the row, as we don't select header rows anymore,
so header cell -> cell -> row

amanmahajan7
amanmahajan7 previously approved these changes Feb 20, 2026
@nstepien nstepien enabled auto-merge (squash) February 20, 2026 17:48
@nstepien nstepien merged commit 90a8fe8 into main Feb 20, 2026
2 checks passed
@nstepien nstepien deleted the nosink branch February 20, 2026 17:50
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.

a11y: focus sink element needs aria-* or role in treegrid mode

3 participants