Skip to content

Commit 333f257

Browse files
committed
feat: add dnb-skip-link support in core style with info under the "focus" docs
1 parent e19c1ce commit 333f257

5 files changed

Lines changed: 79 additions & 8 deletions

File tree

packages/dnb-design-system-portal/src/pages/uilib/usage/accessibility/focus.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ From the technical side, we have to assign an _invisible_ focus, so the user can
2828
The `dnb-ui-lib` has an build in helper, to manage basic focus handling.
2929
This helper also handles both the `tabindex="-1"` and the `class="dnb-no-focus"` situation.
3030

31+
### Focus helper
32+
3133
```js
3234
import {
3335
setPageFocusElement,
@@ -48,3 +50,34 @@ applyPageFocus('MyCustomName')
4850
- also set the focus back to the content, once the menu or navigation area gets closed.
4951

5052
A more complex focus management is build in already to the [Modal Component](/uilib/components/modal). There we actually also disable focus possibility on the content behind, so the user only can navigate inside the modal.
53+
54+
### Skip Link
55+
56+
The `dnb-ui-lib` also has a small setup for a [skip link](https://www.w3.org/TR/WCAG20-TECHS/G1.html)
57+
58+
Our solution is CSS only and should work for all kinds of App setups.
59+
Place an Anchor like this one blow, on the very top of Your App content:
60+
61+
<!-- prettier-ignore-start -->
62+
```html
63+
<a class="dnb-skip-link dnb-button" href="#dnb-app-content">Skip to content</a>
64+
```
65+
<!-- prettier-ignore-end -->
66+
67+
Also, place a `id="dnb-app-content"` on Your content wrapper:
68+
69+
<!-- prettier-ignore-start -->
70+
```html
71+
<body>
72+
<a class="dnb-skip-link dnb-button" href="#dnb-app-content">Skip to content</a>
73+
<header>
74+
<nav>
75+
<!-- Nav links to skip -->
76+
</nav>
77+
</header>
78+
<main id="dnb-app-content">
79+
<!-- Content goes here -->
80+
</main>
81+
</body>
82+
```
83+
<!-- prettier-ignore-end -->

packages/dnb-design-system-portal/src/shared/menu/SidebarMenu.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ export default class SidebarLayout extends PureComponent {
443443
{isOpen && (
444444
<Global
445445
styles={css`
446-
.dnb-page-content {
446+
.dnb-app-content {
447447
display: none !important;
448448
}
449449
`}

packages/dnb-design-system-portal/src/shared/menu/ToggleGrid.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export default class ToggleGrid extends Component {
6969
}
7070
showGrid = showGrid => {
7171
if (typeof document !== 'undefined') {
72-
const page = document.querySelector('.dnb-page-content')
72+
const page = document.querySelector('.dnb-app-content')
7373
if (page) {
7474
if (showGrid) {
7575
page.classList.add('dev-grid')

packages/dnb-design-system-portal/src/shared/parts/Layout.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Sidebar from '../menu/SidebarMenu'
1313
import StickyMenuBar from '../menu/StickyMenuBar'
1414
import { markdownStyle } from './Markdown'
1515
import styled from '@emotion/styled'
16+
import { css, Global } from '@emotion/core'
1617
import classnames from 'classnames'
1718
import { buildVersion } from '../../../package.json'
1819
import { MainMenuProvider } from '../menu/MainMenuContext'
@@ -25,7 +26,7 @@ class Layout extends PureComponent {
2526
}
2627
componentDidMount() {
2728
// gets aplyed on "onRouteUpdate"
28-
setPageFocusElement('.dnb-page-content h1:nth-of-type(1)', 'content')
29+
setPageFocusElement('.dnb-app-content h1:nth-of-type(1)', 'content')
2930
}
3031
render() {
3132
const { children, location } = this.props
@@ -36,7 +37,7 @@ class Layout extends PureComponent {
3637
{/* Load the StickyMenuBar to make use of the grid demo */}
3738
<StickyMenuBar preventBarVisibility={true} />
3839
<Content className="fullscreen-page">
39-
<MaxWidth className="dnb-page-content-inner">
40+
<MaxWidth className="dnb-app-content-inner">
4041
{children}
4142
</MaxWidth>
4243
</Content>
@@ -48,12 +49,16 @@ class Layout extends PureComponent {
4849
return (
4950
<MainMenuProvider>
5051
<SidebarMenuProvider>
52+
<Global styles={globalStyles} />
53+
<a className="dnb-skip-link dnb-button" href="#dnb-app-content">
54+
Skip to content
55+
</a>
5156
<MainMenu enableOverlay />
5257
<StickyMenuBar />
5358
<Wrapper className="content-wrapper">
5459
<Sidebar location={location} showAll={false} />
5560
<Content>
56-
<MaxWidth className="dnb-page-content-inner">
61+
<MaxWidth className="dnb-app-content-inner">
5762
{children}
5863
<Footer />
5964
</MaxWidth>
@@ -67,6 +72,14 @@ class Layout extends PureComponent {
6772

6873
export default Layout
6974

75+
const globalStyles = css`
76+
@media (max-width: 40em) {
77+
a.dnb-skip-link {
78+
display: none;
79+
}
80+
}
81+
`
82+
7083
const Wrapper = styled.div`
7184
position: relative;
7285
z-index: 2;
@@ -82,9 +95,10 @@ const Wrapper = styled.div`
8295
const Content = ({ className, children }) => (
8396
<Main
8497
tabIndex="-1"
98+
id="dnb-app-content"
8599
className={classnames(
86100
'dnb-style',
87-
'dnb-page-content',
101+
'dnb-app-content',
88102
'dnb-no-focus',
89103
className
90104
)}
@@ -121,7 +135,7 @@ const Main = styled.main`
121135
height of StickyMenuBar - 1px border */
122136
padding-top: 4rem;
123137
124-
.dnb-page-content-inner {
138+
.dnb-app-content-inner {
125139
display: flex;
126140
flex-direction: column;
127141
justify-content: space-between;

packages/dnb-ui-lib/src/style/core/dnb-core.scss

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,37 @@ html[data-whatinput='keyboard'] .dnb-style *:not(a):not(div):focus {
4444
}
4545
}
4646

47+
// How to use the "skip-link"
48+
// 1. Have this on the top of Your App: <a class="dnb-skip-link dnb-button" href="#dnb-app-content">Skip to content</a>
49+
// 2. Place this id="dnb-app-content" on Your main content container
50+
a.dnb-skip-link {
51+
position: fixed;
52+
z-index: -9999;
53+
top: -100vh;
54+
overflow: hidden;
55+
}
56+
a.dnb-skip-link:focus,
57+
a.dnb-skip-link:active {
58+
z-index: 9999;
59+
top: auto;
60+
width: auto;
61+
62+
margin: 1rem 45vw;
63+
padding-left: 1rem;
64+
padding-right: 1rem;
65+
66+
@include allBelow(small) {
67+
margin: 1rem 35%;
68+
}
69+
}
70+
4771
// Layout management
4872
// Use this class where components are trying to add background boxes/borders/lines
4973
// to the very outer sides of the page
5074
// e.g. Tabs are using this technique
5175
// In some cases we dont want to have that effect.
5276
// E.g. if we have a menu to the left or right side
53-
.dnb-page-content-inner {
77+
.dnb-app-content-inner {
5478
overflow: hidden;
5579
}
5680

0 commit comments

Comments
 (0)