Skip to content

Commit

Permalink
add skip navigation button
Browse files Browse the repository at this point in the history
  • Loading branch information
HH: Andrico Karoulla committed Jan 21, 2021
1 parent 1e29aed commit d5d4a47
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 2 deletions.
14 changes: 13 additions & 1 deletion cypress/integration/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,24 @@ describe('Navigation', () => {

ListPage.waitUntilVisible();

cy.get('body').tab().tab().tab();
cy.get('body').tab().tab().tab().tab();

cy.get(`${ListPage.elements.menuItems}:first-child`).should(
'have.class',
'Mui-focusVisible'
);
});
});

describe('Skip Navigation Button', () => {
it('should appear when a user immediately tabs on the homepage', () => {
ListPage.navigate();

ListPage.waitUntilVisible();

cy.get('body').tab();

cy.get(ListPage.elements.skipNavButton).should('exist');
});
});
});
1 change: 1 addition & 0 deletions cypress/support/ListPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default url => ({
title: '#react-admin-title',
headroomUnfixed: '.headroom--unfixed',
headroomUnpinned: '.headroom--unpinned',
skipNavButton: '.skip-nav-button',
},

navigate() {
Expand Down
1 change: 1 addition & 0 deletions packages/ra-language-english/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ const englishMessages: TranslationMessages = {
page_rows_per_page: 'Rows per page:',
next: 'Next',
prev: 'Prev',
skip_nav: 'Skip to content',
},
sort: {
sort_by: 'Sort by %{field} %{order}',
Expand Down
70 changes: 70 additions & 0 deletions packages/ra-ui-materialui/src/button/SkipNavigationButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from './Button';
import { useTranslate } from 'ra-core';
import classnames from 'classnames';

function skipToContent() {
const element = document.getElementById('main-content');

if (!element) {
if (process.env.NODE_ENV !== 'production') {
console.warn(
'No element with id "main-content" was found. Ensure the element that contains your main content has an id of "main-content".'
);
}

return;
}

element.setAttribute('tabIndex', '-1');
element.focus();
element.blur();
element.removeAttribute('tabIndex');
}

const useStyles = makeStyles(theme => ({
skipToContentButton: {
position: 'fixed',
padding: theme.spacing(1),
backgroundColor: theme.palette.background.default,
color: theme.palette.getContrastText(theme.palette.background.default),
transition: theme.transitions.create(['top', 'opacity'], {
easing: theme.transitions.easing.easeIn,
duration: theme.transitions.duration.leavingScreen,
}),
left: theme.spacing(2),
top: theme.spacing(-10),
zIndex: 5000,
'&:hover': {
opacity: 0.8,
backgroundColor: theme.palette.background.default,
},
'&:focus': {
top: theme.spacing(2),
transition: theme.transitions.create(['top', 'opacity'], {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
},
},
}));

function SkipNavigationButton() {
const classes = useStyles();
const translate = useTranslate();

return (
<Button
onClick={skipToContent}
className={classnames(
classes.skipToContentButton,
'skip-nav-button'
)}
label={translate('ra.navigation.skip_nav')}
variant="contained"
/>
);
}

export default SkipNavigationButton;
4 changes: 3 additions & 1 deletion packages/ra-ui-materialui/src/layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import DefaultMenu, { MenuProps } from './Menu';
import DefaultNotification from './Notification';
import DefaultError from './Error';
import defaultTheme from '../defaultTheme';
import SkipNavigationButton from '../button/SkipNavigationButton';

const styles = theme =>
createStyles({
Expand Down Expand Up @@ -130,6 +131,7 @@ class LayoutWithoutTheme extends Component<
className={classnames('layout', classes.root, className)}
{...props}
>
<SkipNavigationButton />
<div className={classes.appFrame}>
{createElement(appBar, { title, open, logout })}
<main className={classes.contentWithSidebar}>
Expand All @@ -139,7 +141,7 @@ class LayoutWithoutTheme extends Component<
hasDashboard: !!dashboard,
}),
})}
<div className={classes.content}>
<div id="main-content" className={classes.content}>
{hasError
? createElement(error, {
error: errorMessage,
Expand Down

0 comments on commit d5d4a47

Please sign in to comment.