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

[DataGrid] Fix VoiceOver reading the column name twice #14482

Merged
merged 5 commits into from
Sep 11, 2024

Conversation

arminmeh
Copy link
Contributor

@arminmeh arminmeh commented Sep 4, 2024

Fixes #9954

aria-label was only added if the default header component was used (GridColumnHeaderTitle).
That component adds label as its content which is read by the voice over, so the aria-label is not needed at all.

@arminmeh arminmeh added bug 🐛 Something doesn't work accessibility a11y component: data grid This is the name of the generic UI component, not the React module! labels Sep 4, 2024
@arminmeh arminmeh requested a review from a team September 4, 2024 08:07
@mui-bot
Copy link

mui-bot commented Sep 4, 2024

Deploy preview: https://deploy-preview-14482--material-ui-x.netlify.app/

Generated by 🚫 dangerJS against ae67fd4

Copy link
Member

@KenanYusuf KenanYusuf left a comment

Choose a reason for hiding this comment

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

Tested with VoiceOver and it is working as expected.

@@ -111,7 +111,6 @@ const GridGenericColumnHeaderItem = React.forwardRef(function GridGenericColumnH
tabIndex={tabIndex}
aria-colindex={colIndex + 1}
aria-sort={ariaSort}
aria-label={headerComponent == null ? label : undefined}
Copy link
Member

Choose a reason for hiding this comment

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

I looked into this issue some time ago, but couldn't make it work properly.
Even with this change, it doesn't seem to work as expected – see the recording:

Screen.Recording.2024-09-04.at.19.24.04.mov

Any idea why it starts reading the column name twice?

Copy link
Member

Choose a reason for hiding this comment

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

Which keys are you using to navigate the header items? 🤔

Copy link
Member

Choose a reason for hiding this comment

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

Control + Option + arrow keys

Copy link
Contributor Author

@arminmeh arminmeh Sep 5, 2024

Choose a reason for hiding this comment

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

I found the reason
it looks like the Tooltip component is adding another aria-label on the wrapped component

<rootProps.slots.baseTooltip
title={description || tooltip}
{...rootProps.slotProps?.baseTooltip}
>
<ColumnHeaderInnerTitle onMouseOver={handleMouseOver} ref={titleRef}>
{label}
</ColumnHeaderInnerTitle>
</rootProps.slots.baseTooltip>
);

we don't pass it here, but consoling other in

const ColumnHeaderInnerTitle = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(function ColumnHeaderInnerTitle(props, ref) {
const { className, ...other } = props;
const rootProps = useGridRootProps();
const classes = useUtilityClasses(rootProps);
return (
<GridColumnHeaderTitleRoot
ref={ref}
className={clsx(classes.root, className)}
ownerState={rootProps}
{...other}
/>
);
});

shows aria-label prop

For string content, aria-label should not be attached to the element. For now, I will filter it out in our component, but I will make a PR to the component to fix it there as well (Tooltip can't predict what the content will be. Solution might be not to add aria attribute and leave it to devs to attach it to their custom component, but that would be a breaking change, so I will leave it as is)

Update
aria-label should still be removed, but that didn't help. What I have found out is that this is actually Chrome issue. I did the test in the plain table as suggested and confirmed that the same occurs there. In Safari it works fine.

I think that the voice over wants to connect header name with the cell when you use Control + Option + arrow keys. If you navigate through content you will notice that it reads out the data plus the column name which is great in that scenario.

Anyway, I think that we can ignore that issue and have at least regular arrow key navigation fixed

Copy link
Member

Choose a reason for hiding this comment

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

Control + Option + arrow keys

Ah makes sense, I tested with the arrow keys only, not the virtual cursor.

I think that the voice over wants to connect header name with the cell when you use Control + Option + arrow keys. If you navigate through content you will notice that it reads out the data plus the column name which is great in that scenario.

Strange bug.

Anyway, I think that we can ignore that issue and have at least regular arrow key navigation fixed

I tested again with the latest changes and it's working as expected with arrow keys at least 👍

@arminmeh arminmeh force-pushed the column-header-accessibility branch from babdf09 to 8d5aba7 Compare September 5, 2024 07:41
@@ -29,5 +29,5 @@ export const GRID_DETAIL_PANEL_TOGGLE_COL_DEF: GridColDef = {
return expandedRowIds.includes(rowId);
},
renderCell: (params) => <GridDetailPanelToggleCell {...params} />,
renderHeader: () => null,
renderHeader: (params) => <div aria-label={params.colDef.headerName} />,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Before, the condition headerComponent == null ? label : undefined in GridGenericColumnHeaderItem was ensuring that the aria label is added to this column without actually rendering anything.
Now the column definition holds that logic in itself

Copy link
Member

Choose a reason for hiding this comment

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

How about we do this internally instead?

diff --git a/packages/x-data-grid-pro/src/hooks/features/detailPanel/gridDetailPanelToggleColDef.tsx b/packages/x-data-grid-pro/src/hooks/features/detailPanel/gridDetailPanelToggleColDef.tsx
index 0fc2a55a78..ce3a18b882 100644
--- a/packages/x-data-grid-pro/src/hooks/features/detailPanel/gridDetailPanelToggleColDef.tsx
+++ b/packages/x-data-grid-pro/src/hooks/features/detailPanel/gridDetailPanelToggleColDef.tsx
@@ -29,5 +29,5 @@ export const GRID_DETAIL_PANEL_TOGGLE_COL_DEF: GridColDef = {
     return expandedRowIds.includes(rowId);
   },
   renderCell: (params) => <GridDetailPanelToggleCell {...params} />,
-  renderHeader: (params) => <div aria-label={params.colDef.headerName} />,
+  renderHeader: () => null,
 };
diff --git a/packages/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx b/packages/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx
index 412bb46be9..91ecd13dc5 100644
--- a/packages/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx
+++ b/packages/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx
@@ -120,7 +120,7 @@ const GridGenericColumnHeaderItem = React.forwardRef(function GridGenericColumnH
         <div className={classes.titleContainer} role="presentation">
           <div className={classes.titleContainerContent}>
             {headerComponent !== undefined ? (
-              headerComponent
+              headerComponent || <div aria-label={label} />
             ) : (
               <GridColumnHeaderTitle label={label} description={description} columnWidth={width} />
             )}

Copy link
Contributor Author

@arminmeh arminmeh Sep 5, 2024

Choose a reason for hiding this comment

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

I would rather keep it with the definition that actually needs it and keep the generic component clean from it.
Otherwise we have this (for me) weird algorithm where we say:

  • If you don't provide a component a fallback will be rendered
  • Else If your component is null another fallback will be rendered
  • Else your component is rendered

Searching the code, I didn't find any other place where null is returned (there is another definition with ' ', but that will not end up in the same code branch)

Do you think that someone relies on the current logic and that the things will break?

Copy link
Member

Choose a reason for hiding this comment

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

I was mostly considering compatibility here, but also a better default – no need to know this trick to make the column header accessible.
The empty column header is a rare case though.
I don't have a strong opinion on this one, I'm OK with your approach 👍🏻

Copy link
Member

@MBilalShafi MBilalShafi left a comment

Choose a reason for hiding this comment

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

Looks great on Firefox and Chrome with Arrow keys. 🎉
Found a small issue on Safari, feel free to handle it separately if it's unrelated.

Copy link
Member

@MBilalShafi MBilalShafi Sep 9, 2024

Choose a reason for hiding this comment

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

Might be unrelated to this PR but Safari [Version 17.5 (19618.2.12.11.6)] reads normal cells twice too (used to do for header cells too but fixed with this PR)

voiceover-safari.mp4

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, this is what I saw as well
since it is not mentioned in the original issue, I have opened a separate PR to address this

arminmeh and others added 5 commits September 11, 2024 23:26
Co-authored-by: Bilal Shafi <bilalshafidev@gmail.com>
Signed-off-by: Armin Mehinovic <4390250+arminmeh@users.noreply.github.com>
@arminmeh arminmeh force-pushed the column-header-accessibility branch from f9d8da6 to ae67fd4 Compare September 11, 2024 21:26
@arminmeh arminmeh merged commit 3072871 into mui:master Sep 11, 2024
16 checks passed
@arminmeh arminmeh deleted the column-header-accessibility branch September 11, 2024 22:07
arthurbalduini pushed a commit to arthurbalduini/mui-x that referenced this pull request Sep 30, 2024
Signed-off-by: Armin Mehinovic <4390250+arminmeh@users.noreply.github.com>
Co-authored-by: Bilal Shafi <bilalshafidev@gmail.com>
@oliviertassinari oliviertassinari changed the title [DataGrid] Fix Voice Over reading the column name twice [DataGrid] Fix VoiceOver reading the column name twice Oct 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accessibility a11y bug 🐛 Something doesn't work component: data grid This is the name of the generic UI component, not the React module!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[data grid] Column name has been read out twice by macOS VoiceOver
5 participants