Skip to content

Commit

Permalink
[EuiSkipLink] Add array support for fallbackDestination prop (#6646)
Browse files Browse the repository at this point in the history
* Add array support for `fallbackDestination` prop

Kibana neeeds this 🥲

* Changelog
  • Loading branch information
cee-chen authored Mar 20, 2023
1 parent 2c7ba32 commit e76c07e
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 6 deletions.
29 changes: 27 additions & 2 deletions src/components/accessibility/skip_link/skip_link.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,40 @@ describe('EuiSkipLink', () => {
<>
<EuiSkipLink
destinationId=""
fallbackDestination="main, [role=main]"
fallbackDestination="main, [role=main], .appWrapper"
>
Skip to content
</EuiSkipLink>
<div role="main">I am content</div>
<div className="appWrapper">
<div role="main">I am content</div>
</div>
</>
);
fireEvent.click(getByText('Skip to content'));

// Unlike the array behavior, querySelector always picks *the first node in the DOM tree* found
// vs. the first item in the selector comma string
const expectedFocus = document.querySelector('.appWrapper');
expect(document.activeElement).toEqual(expectedFocus);
});

it('supports an array of query selectors', () => {
const { getByText } = render(
<>
<EuiSkipLink
destinationId=""
fallbackDestination={['main', '[role=main]', '.appWrapper']}
>
Skip to content
</EuiSkipLink>
<div className="appWrapper">
<div role="main">Test</div>
</div>
</>
);
fireEvent.click(getByText('Skip to content'));

// Array syntax allows us to prioritize preferred selectors
const expectedFocus = document.querySelector('[role=main]');
expect(document.activeElement).toEqual(expectedFocus);
});
Expand Down
19 changes: 15 additions & 4 deletions src/components/accessibility/skip_link/skip_link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,15 @@ interface EuiSkipLinkInterface extends EuiButtonProps {
*/
destinationId: string;
/**
* If no destination ID element exists or can be found, you may provide a string of
* query selectors to fall back to (e.g. a `main` or `role="main"` element)
* If no destination ID element exists or can be found, you may provide a query selector
* string to fall back to.
*
* For complex applications with potentially variable layouts per page, an array of
* query selectors can be passed, e.g. `['main', '[role=main]', '.appWrapper']`, which
* prioritizes looking for multiple fallbacks based on array order.
* @default main
*/
fallbackDestination?: string;
fallbackDestination?: string | string[];
/**
* If default HTML anchor link behavior is not desired (e.g. for SPAs with hash routing),
* setting this flag to true will manually scroll to and focus the destination element
Expand Down Expand Up @@ -83,7 +87,14 @@ export const EuiSkipLink: FunctionComponent<EuiSkipLinkProps> = ({
const hasValidId = !!destinationEl;
// Check the fallback destination if not
if (!destinationEl && fallbackDestination) {
destinationEl = document.querySelector(fallbackDestination);
if (Array.isArray(fallbackDestination)) {
for (let i = 0; i < fallbackDestination.length; i++) {
destinationEl = document.querySelector(fallbackDestination[i]);
if (destinationEl) break; // Stop once the first fallback has been found
}
} else {
destinationEl = document.querySelector(fallbackDestination);
}
}

if ((overrideLinkBehavior || !hasValidId) && destinationEl) {
Expand Down
1 change: 1 addition & 0 deletions upcoming_changelogs/6646.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Updated `EuiSkipLink`'s `fallbackDestination` prop to support an array of query selector strings

0 comments on commit e76c07e

Please sign in to comment.