Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[data grid] Skip tab focus on custom cell #11999

Closed
Edelf opened this issue Feb 8, 2024 · 17 comments
Closed

[data grid] Skip tab focus on custom cell #11999

Edelf opened this issue Feb 8, 2024 · 17 comments
Labels
accessibility a11y component: data grid This is the name of the generic UI component, not the React module! status: waiting for author Issue with insufficient information support: commercial Support request from paid users

Comments

@Edelf
Copy link

Edelf commented Feb 8, 2024

The problem in depth

For context, the following scenario is a consequence of the solution proposed on the following issue: #9489

When using the keyboard tab to navigate between cells, I need to skip a specific cell that displays the result of a calculation. This cell cannot be flagged as editable: false since it needs to display the result in real-time whenever the other cells are changed.

https://codesandbox.io/p/devbox/5jyv2k?file=%2Fsrc%2FDemo.tsx
On the example above, cell Total is the result of Quantity * Price. ✅
Whenever Quantity or Price changes, Total needs to update. ✅
Using the keyboard to navigate from cell to cell, I need to be able to reach the last cell Other, skipping/without focusing Total similar to if the cell was editable: false

How can I achieve this?

Your environment

`npx @mui/envinfo`
  Don't forget to mention which browser you used.
  Output from `npx @mui/envinfo` goes here.

Search keywords: tab, focus, keyboard navigation
Order ID: 68154

@Edelf Edelf added status: waiting for maintainer These issues haven't been looked at yet by a maintainer support: commercial Support request from paid users labels Feb 8, 2024
@Edelf Edelf changed the title [question] Skip tab focus on custom cell [question][DataGrid] Skip tab focus on custom cell Feb 8, 2024
@michelengelen michelengelen changed the title [question][DataGrid] Skip tab focus on custom cell [data grid] Skip tab focus on custom cell Feb 9, 2024
@michelengelen
Copy link
Member

Hi @Edelf
First of all thanks for using the data grid.

Your use case is indeed interesting.

  1. You can make the col editable: false that won't break the calculation and update.
  2. skipping a cell is against the accessibility standards, so it is not possible OOTB.

I am not sure if this is possible at all. Let me check that.

@michelengelen michelengelen added accessibility a11y component: data grid This is the name of the generic UI component, not the React module! labels Feb 9, 2024
@Edelf
Copy link
Author

Edelf commented Feb 9, 2024

Hi @michelengelen , thank you for the reply.

Setting the col to editable: false creates a de-synchronization between what is presented and the grid state.
https://codesandbox.io/p/devbox/clever-chaplygin-6pq5x4?file=%2Fsrc%2FDemo.tsx%3A108%2C21

In the example above, whenever we change the Quantity, the Total is visually updated, but if you look at the processRowUpdate log, Total remains unchanged.

@michelengelen
Copy link
Member

Ah, yes. I forgot about that. My bad 🙇🏼
Well ... I am currently exploring a bit on this topic. I do think this is generally possible by using the onCellKeyDown grid method and the apiRef checking for a custom attribute in the ColDef (skipFocus or similar).

The reason for the keydown handler is that with this we can determine where the focus comes from and if we need to skip the next field or not.

Stay tuned ... I will have an answer today!

@michelengelen
Copy link
Member

Ok, I managed to build an example for your use case: Skip column on keyboard navigation

It makes use of the before mentioned methods and ideas (to some extent).

Have a look an tell me if this is something you can use!
Thanks! 🙇🏼

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Feb 9, 2024
@Edelf
Copy link
Author

Edelf commented Feb 9, 2024

I adapted your proposed solution to my usecase and it's not working properly with TAB and SHIFT+TAB and editMode='row':
https://stackblitz.com/edit/react-wsb1ap-nokwtk?file=Demo.tsx

It would also increase considerably the complexity of the solution taking into consideration some dynamic columns and custom cells.

Thank you again for the reply and time spent on this.

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Feb 9, 2024
@michelengelen
Copy link
Member

Ah, I was not aware that you were referring to the row being in edit mode.
It is very likely that the approach I took could also be use dot achieve what you are trying.
But maybe there is a better way I am just not able to see at the moment. @MBilalShafi would there be something you can think of to achieve the desired behavior?

@MBilalShafi
Copy link
Member

MBilalShafi commented Feb 13, 2024

@Edelf Your use-case is indeed an interesting one.

I think you can use the initial recommendation by @michelengelen of making the column editable: false to achieve the first part of the required solution, i.e. to skip focusing the total column.

Now, the problem the value is not correctly being computed in the row passed to the processRowUpdate is the limitation of the valueSetter, which only works for editable columns as stated here:

* It only works with cell/row editing.

But if you read the explanation of the processRowUpdate callback in the related documentation, it says:

Please note that the processRowUpdate must return the row object to update the Data Grid internal state.

You can use this for your benefit to set the correct value for the total column on every row update.

<DataGrid
  processRowUpdate={(recievedRow: GridValidRowModel) => {
    console.log("recievedRow", recievedRow); // includes incorrect value for `total`
    const updatedRow = {
      ...recievedRow,
      total: computeTotal(recievedRow).valueOf(), // update the value
    };
    return updatedRow; // update the value in Grid's state
  }}
/>

Now it solves the problem of value not synchronizing with the Grid state, but another problem is still there which was previously being solved by the valueSetter, i.e. the updated value is not shown in the cell before the row is saved (processRowUpdate is called)

You can solve this by passing a custom cell to the renderCell parameter of the column total, which computes the value based on the values of the columns it depends on.

I tried to do that in this csb example. Let me know if it solves your use cases.

Thank You.

@MBilalShafi MBilalShafi added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Feb 13, 2024
@Edelf
Copy link
Author

Edelf commented Feb 13, 2024

Thank you @MBilalShafi / @michelengelen for the time you spent on this.

I tried to simplify our use cases on my initial post, and for that case your proposed solution would work!
However we have other situations that cannot use that solution.

For instance (built on top of your solution): https://stackblitz.com/edit/react-wsb1ap-6eu6rq?file=Demo.tsx
The column Editable if odd is dynamically editable/readonly depending if the current value of Quantity is odd or even
In this case, we cannot rely on processRowUpdate+editable: false, and we need to be able to tab "over" Editable if odd if it is currently readonly.

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Feb 13, 2024
@zannager zannager removed the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Feb 15, 2024
@Edelf
Copy link
Author

Edelf commented Feb 16, 2024

@zannager any specific reason for that status change?

@MBilalShafi MBilalShafi added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Feb 18, 2024
@MBilalShafi
Copy link
Member

MBilalShafi commented Feb 18, 2024

@Edelf Does isCellEditable (the commented part in the last example) not work for your use case?

@MBilalShafi MBilalShafi added status: waiting for author Issue with insufficient information and removed component: data grid This is the name of the generic UI component, not the React module! labels Feb 18, 2024
@Edelf
Copy link
Author

Edelf commented Feb 20, 2024

@MBilalShafi here is the example, using isCellEditable: https://stackblitz.com/edit/react-wsb1ap-6eu6rq?file=Demo.tsx
If you go into edit mode, change the quantity from 25 to 26, you can no longer tab to Last Editable Col.
If you commit the line after changing from 25 to 26, then edit again, then you can tab Last Editable Col.

@github-actions github-actions bot removed the status: waiting for author Issue with insufficient information label Feb 20, 2024
@michelengelen michelengelen added the component: data grid This is the name of the generic UI component, not the React module! label Feb 21, 2024
@MBilalShafi
Copy link
Member

Thanks for adding the advanced use case.

It's because, until the edit change is not committed, we keep passing the previous row values to the isCellEditable prop due to which the Editable if odd is always computed to be editable but the edit input cell is not anymore available because of the use of apiRef.current.getRowWithUpdatedValues(id, field) in renderEditCell.

IMO, we can pass the non-committed updated row values to the isCellEditable to handle such use cases. I've raised a PR on the same idea.

Here is a demo based on that PR built on top of the last demo you shared: https://codesandbox.io/p/sandbox/to-delete-forked-jn874w?file=%2Fsrc%2FApp.tsx%3A218%2C29

Let me know if it'll solve your issue.

@MBilalShafi MBilalShafi removed the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Feb 28, 2024
@michelengelen michelengelen added the status: waiting for author Issue with insufficient information label Feb 28, 2024
@Edelf
Copy link
Author

Edelf commented Feb 28, 2024

@MBilalShafi thank you again for your time.

Your example works, except for:

  • If you change the Quantity to 21, you can TAB to the last column, but you cannot SHIFT+TAB out of the last column
  • The styles (isCellDisabledClassName) is not updated until you commit the line

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Feb 28, 2024
@MBilalShafi
Copy link
Member

MBilalShafi commented Mar 4, 2024

If you change the Quantity to 21, you can TAB to the last column, but you cannot SHIFT+TAB out of the last column

I can not reproduce it, for me both TAB and SHIFT + TAB work as expected. Could you check again and possibly share the reproduce steps if that may help?

The styles (isCellDisabledClassName) is not updated until you commit the line

That's because the cell is by default memoized for performance reasons and is not re-rendered until there is a state update (or processRowUpdate is fired) and the cellClassName is not recomputed.
You could change this behavior by providing a custom cell and forcing it to re-render on editState change.

Here's an updated example: https://codesandbox.io/p/sandbox/to-delete-forked-8zqrsm?file=%2Fsrc%2FApp.tsx%3A215%2C26


Update: There's a dependency fetch error with the codesandbox ci packages due to which the sandbox is not rendering properly, I'll look into it in a while, meanwhile you can test the change locally if you want.

@MBilalShafi MBilalShafi added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Mar 4, 2024
@Edelf
Copy link
Author

Edelf commented Mar 5, 2024

Here is a screen recording of your latest codesandbox showing the tab behavior:
firefox_7fJgiRi2F7

Thank you again for looking into this :)

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Mar 5, 2024
@MBilalShafi
Copy link
Member

MBilalShafi commented Mar 15, 2024

Hey @Edelf, first of all, apologies for getting back to you so late, I was caught up with many things.

After analyzing the problem again, I think the root of the problem is the row edit not being committed when a cell is switched using Tab or Shift + Tab due to which we had to introduce many hacks in the examples above, still not able to solve all the problems. The row editing is by definition designed not to update the values in the state before the row change is committed.

An alternate way could be to use cell editing, using which we could build a similar solution (it could even be better since the Tab navigation works on multiple rows)

Here's the example I built on top of the single-click editing demo which might give a similar experience with the interactions smoother and the Tab navigation fixed: https://stackblitz.com/edit/react-u9chwq-nvpr8h?file=Demo.tsx,package.json,GridCell.tsx,node_modules%2F%40mui%2Fx-data-grid%2Fmodels%2FcolDef%2FgridColDef.d.ts

A small test on the above demo:

tab.mp4

I'd appreciate you checking it out and letting me know if this is a direction you can go forward with!

Thank you!

@MBilalShafi MBilalShafi added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Mar 15, 2024
Copy link

The issue has been inactive for 7 days and has been automatically closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accessibility a11y component: data grid This is the name of the generic UI component, not the React module! status: waiting for author Issue with insufficient information support: commercial Support request from paid users
Projects
None yet
Development

No branches or pull requests

4 participants