mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Accessibility: Add Skip to content link (#68065)
* user essentials mob! 🔱 lastFile:public/app/core/components/AppChrome/AppChrome.tsx * user essentials mob! 🔱 lastFile:public/app/core/components/AppChrome/AppChrome.test.tsx * only show skiplink when page has app chrome --------- Co-authored-by: Joao Silva <joao.silva@grafana.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { KBarProvider } from 'kbar';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
@@ -109,4 +110,28 @@ describe('AppChrome', () => {
|
||||
expect(screen.getByRole('tab', { name: 'Tab Child1' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('tab', { name: 'Tab pageNav child1' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should create a skip link to skip to main content', async () => {
|
||||
setup(<Page navId="child1">Children</Page>);
|
||||
expect(await screen.findByRole('link', { name: 'Skip to main content' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should focus the skip link on initial tab before carrying on with normal tab order', async () => {
|
||||
setup(<Page navId="child1">Children</Page>);
|
||||
await userEvent.keyboard('{tab}');
|
||||
const skipLink = await screen.findByRole('link', { name: 'Skip to main content' });
|
||||
expect(skipLink).toHaveFocus();
|
||||
await userEvent.keyboard('{tab}');
|
||||
expect(await screen.findByRole('link', { name: 'Go to home' })).toHaveFocus();
|
||||
});
|
||||
|
||||
it('should not render a skip link if the page is chromeless', async () => {
|
||||
const { context } = setup(<Page navId="child1">Children</Page>);
|
||||
context.chrome.update({
|
||||
chromeless: true,
|
||||
});
|
||||
waitFor(() => {
|
||||
expect(screen.queryByRole('link', { name: 'Skip to main content' })).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import classNames from 'classnames';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
|
||||
import { GrafanaTheme2, PageLayoutType } from '@grafana/data';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
import { useStyles2, LinkButton } from '@grafana/ui';
|
||||
import { useGrafana } from 'app/core/context/GrafanaContext';
|
||||
import { CommandPalette } from 'app/features/commandPalette/CommandPalette';
|
||||
import { KioskMode } from 'app/types';
|
||||
@@ -34,8 +34,12 @@ export function AppChrome({ children }: Props) {
|
||||
// doesn't get re-mounted when chromeless goes from true to false.
|
||||
|
||||
return (
|
||||
<main className={classNames('main-view', searchBarHidden && 'main-view--search-bar-hidden')}>
|
||||
<div className={classNames('main-view', searchBarHidden && 'main-view--search-bar-hidden')}>
|
||||
{!state.chromeless && (
|
||||
<>
|
||||
<LinkButton className={styles.skipLink} href="#pageContent">
|
||||
Skip to main content
|
||||
</LinkButton>
|
||||
<div className={cx(styles.topNav)}>
|
||||
{!searchBarHidden && <TopSearchBar />}
|
||||
<NavToolbar
|
||||
@@ -48,20 +52,21 @@ export function AppChrome({ children }: Props) {
|
||||
onToggleKioskMode={chrome.onToggleKioskMode}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className={contentClass}>
|
||||
<main className={contentClass} id="pageContent">
|
||||
<div className={styles.panes}>
|
||||
{state.layout === PageLayoutType.Standard && state.sectionNav && <SectionNav model={state.sectionNav} />}
|
||||
<div className={styles.pageContainer}>{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{!state.chromeless && (
|
||||
<>
|
||||
<MegaMenu searchBarHidden={searchBarHidden} onClose={() => chrome.setMegaMenu(false)} />
|
||||
<CommandPalette />
|
||||
</>
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -112,5 +117,15 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
flexGrow: 1,
|
||||
minHeight: 0,
|
||||
}),
|
||||
skipLink: css({
|
||||
position: 'absolute',
|
||||
top: -1000,
|
||||
|
||||
':focus': {
|
||||
left: theme.spacing(1),
|
||||
top: theme.spacing(1),
|
||||
zIndex: theme.zIndex.portal,
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user