Skip to content

Commit

Permalink
[refactor] clean up focus trap aria-describedby text
Browse files Browse the repository at this point in the history
- aria-describedby text doesn't need to be visible at all, we can just use `hidden`, which removes it from the copy clipboard

+ condense down to a single element
  • Loading branch information
cee-chen committed Sep 12, 2024
1 parent f53c710 commit 0b29898
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,8 @@ describe('FocusTrappedChildren', () => {
data-focus-lock-disabled="disabled"
>
<p
aria-hidden="true"
class="emotion-euiScreenReaderOnly"
id="euiDataGridCellHeader_generated-id_exited"
/>
<p
aria-hidden="true"
class="emotion-euiScreenReaderOnly"
id="euiDataGridCellHeader_generated-id_keyboardHint"
hidden=""
id="generated-id_focusTrapHint"
>
Press the Enter key to interact with this cell's contents.
</p>
Expand Down
82 changes: 38 additions & 44 deletions packages/eui/src/components/datagrid/body/cell/focus_utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@ import React, {
import { FocusableElement, tabbable } from 'tabbable';
import classNames from 'classnames';

import { keys } from '../../../../services';
import { useGeneratedHtmlId } from '../../../../services/accessibility';
import { keys, useGeneratedHtmlId } from '../../../../services';
import { isDOMNode } from '../../../../utils';
import { EuiFocusTrap } from '../../../focus_trap';
import { EuiScreenReaderOnly } from '../../../accessibility';
import { EuiI18n } from '../../../i18n';

/**
Expand Down Expand Up @@ -92,14 +90,8 @@ export const FocusTrappedChildren: FunctionComponent<
const [isCellEntered, setIsCellEntered] = useState(false);
const [isExited, setExited] = useState(false);

const keyboardHintAriaId = useGeneratedHtmlId({
prefix: 'euiDataGridCellHeader',
suffix: 'keyboardHint',
});

const exitedHintAriaId = useGeneratedHtmlId({
prefix: 'euiDataGridCellHeader',
suffix: 'exited',
const ariaDescribedById = useGeneratedHtmlId({
suffix: 'focusTrapHint',
});

// direct DOM manipulation as workaround to attach required hints
Expand All @@ -108,9 +100,17 @@ export const FocusTrappedChildren: FunctionComponent<

cellEl.setAttribute(
'aria-describedby',
classNames(currentAriaDescribedbyId, exitedHintAriaId, keyboardHintAriaId)
classNames(currentAriaDescribedbyId, ariaDescribedById)
);
}, [cellEl, keyboardHintAriaId, exitedHintAriaId]);

return () => {
if (currentAriaDescribedbyId) {
cellEl.setAttribute('aria-descibedby', currentAriaDescribedbyId);
} else {
cellEl.removeAttribute('aria-describedby');
}
};
}, [cellEl, ariaDescribedById]);

useEffect(() => {
if (isCellEntered) {
Expand Down Expand Up @@ -173,37 +173,31 @@ export const FocusTrappedChildren: FunctionComponent<
>
{children}

<EuiScreenReaderOnly>
{/**
* Hints use aria-hidden to prevent them from being read as regular content.
* They are still read in JAWS and NVDA via the linking with aria-describedby.
* VoiceOver does generally not read the column on re-focus after exiting a cell,
* which mean the exited hint is not read.
* VoiceOver does react to aria-live (without aria-hidden) but that would causes
* duplicate output in JAWS/NVDA (reading content & live announcement).
* Optimizing for Windows screen readers as they have a larger usages.
*/}
<p id={exitedHintAriaId} aria-hidden="true">
{isExited && (
<EuiI18n
// eslint-disable-next-line local/i18n
token="euiDataGridCell.focusTrapExitPrompt"
default="Exited cell content."
/>
)}
</p>
</EuiScreenReaderOnly>
<EuiScreenReaderOnly>
<p id={keyboardHintAriaId} aria-hidden="true">
{!isCellEntered && (
<EuiI18n
// eslint-disable-next-line local/i18n
token="euiDataGridCell.focusTrapEnterPrompt"
default="Press the Enter key to interact with this cell's contents."
/>
)}
</p>
</EuiScreenReaderOnly>
{/**
* Hints use `hidden` to prevent them from being read by screen readers as regular content.
* They are still read in JAWS and NVDA via the linking with aria-describedby.
* VoiceOver does generally not read the column on re-focus after exiting a cell,
* which mean the exited hint is not read.
* VoiceOver does react to aria-live (without aria-hidden) but that would causes
* duplicate output in JAWS/NVDA (reading content & live announcement).
* Optimizing for Windows screen readers as they have a larger usages.
*/}
<p id={ariaDescribedById} hidden>
{isExited && (
<EuiI18n
// eslint-disable-next-line local/i18n
token="euiDataGridCell.focusTrapExitPrompt"
default="Exited cell content."
/>
)}
{!isCellEntered && (
<EuiI18n
// eslint-disable-next-line local/i18n
token="euiDataGridCell.focusTrapEnterPrompt"
default="Press the Enter key to interact with this cell's contents."
/>
)}
</p>
</EuiFocusTrap>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('EuiDataGridControlHeaderCell', () => {
const { container } = render(<EuiDataGridControlHeaderCell {...props} />);
expect(container.firstChild).toMatchInlineSnapshot(`
<div
aria-describedby="euiDataGridCellHeader_generated-id_exited euiDataGridCellHeader_generated-id_keyboardHint"
aria-describedby="generated-id_focusTrapHint"
class="euiDataGridHeaderCell euiDataGridHeaderCell--controlColumn emotion-euiDataGridHeaderCell"
data-gridcell-column-id="someControlColumn"
data-gridcell-column-index="0"
Expand All @@ -50,14 +50,8 @@ describe('EuiDataGridControlHeaderCell', () => {
tabindex="-1"
/>
<p
aria-hidden="true"
class="emotion-euiScreenReaderOnly"
id="euiDataGridCellHeader_generated-id_exited"
/>
<p
aria-hidden="true"
class="emotion-euiScreenReaderOnly"
id="euiDataGridCellHeader_generated-id_keyboardHint"
hidden=""
id="generated-id_focusTrapHint"
>
Press the Enter key to interact with this cell's contents.
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,8 @@ describe('EuiDataGridHeaderCellWrapper', () => {
Mock column actions
</button>
<p
aria-hidden="true"
class="emotion-euiScreenReaderOnly"
id="euiDataGridCellHeader_generated-id_exited"
/>
<p
aria-hidden="true"
class="emotion-euiScreenReaderOnly"
id="euiDataGridCellHeader_generated-id_keyboardHint"
hidden=""
id="generated-id_focusTrapHint"
>
Press the Enter key to interact with this cell's contents.
</p>
Expand Down

0 comments on commit 0b29898

Please sign in to comment.