Skip to content

Commit

Permalink
feat: adding a skip to search anchor (#850)
Browse files Browse the repository at this point in the history
Co-authored-by: Luke Karrys <[email protected]>
  • Loading branch information
ivan-demchenko and lukekarrys authored Dec 4, 2023
1 parent 298c866 commit e388aee
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 34 deletions.
8 changes: 8 additions & 0 deletions gatsby-browser.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import {SKIP_TO_SEARCH_ID} from './src/constants'

export {default as wrapPageElement} from './src/page'
export {default as wrapRootElement} from './src/root'

export const shouldUpdateScroll = ({routerProps}) => {
const {scrollUpdate = true} = routerProps.location.state ?? {}
return scrollUpdate
}

export const onRouteUpdate = ({location, prevLocation}) => {
if (location.hash === `#${SKIP_TO_SEARCH_ID}` && prevLocation?.hash !== `#${SKIP_TO_SEARCH_ID}`) {
document.getElementById(SKIP_TO_SEARCH_ID)?.focus()
}
}
65 changes: 33 additions & 32 deletions src/components/skip-nav.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,50 @@
import React from 'react'
import {Box} from '@primer/react'
import {Box, themeGet} from '@primer/react'
import styled from 'styled-components'
import Link from './link'
import {SCROLL_MARGIN_TOP} from '../constants'
import {SCROLL_MARGIN_TOP, SKIP_TO_CONTENT_ID} from '../constants'

const ID = 'skip-nav'

const SkipLinkBase = props => (
<Link
{...props}
href={`#${ID}`}
sx={{
p: 3,
color: 'fg.onEmphasis',
backgroundColor: 'accent.emphasis',
fontSize: 1,
}}
>
Skip to content
</Link>
)
export const SkipLink = styled(Link)`
color: ${themeGet('colors.accent.emphasis')};
padding: ${themeGet('space.1')};
&:focus {
text-decoration: underline;
}
`

// The following rules are to ensure that the element is visually hidden, unless
// it has focus. This is the recommended way to hide content from:
// https://webaim.org/techniques/css/invisiblecontent/#techniques
export const SkipLink = styled(SkipLinkBase)`
export const SkipBox = styled.div`
display: inline-flex;
z-index: 20;
width: auto;
height: auto;
clip: auto;
position: absolute;
overflow: hidden;
left: 10px;
gap: 3px;
position: absolute;
transform: translateY(-100%);
transition: transform 0.3s;
padding: ${themeGet('space.2')};
background-color: ${themeGet('colors.canvas.default')};
border: 1px solid ${themeGet('colors.accent.emphasis')};
border-top: 0;
font-size: ${themeGet('fontSizes.1')};
border-radius: 0 0 ${themeGet('radii.2')} ${themeGet('radii.2')};
&:focus-within {
transform: translateY(0%);
}
& > * {
margin-right: ${themeGet('space.1')};
}
&:not(:focus) {
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
padding: 0;
& > *:last-child {
margin-right: 0;
}
`

const SkipNavBase = props => <Box id={ID} {...props} />
const SkipNavBase = props => <Box id={SKIP_TO_CONTENT_ID} {...props} />

export const SkipNav = styled(SkipNavBase)`
scroll-margin-top: ${SCROLL_MARGIN_TOP}px;
Expand Down
4 changes: 4 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ export const FULL_HEADER_HEIGHT = HEADER_HEIGHT + HEADER_BAR

export const SCROLL_MARGIN_TOP = FULL_HEADER_HEIGHT + 24

export const SKIP_TO_CONTENT_ID = 'skip-to-content'

export const SKIP_TO_SEARCH_ID = 'search-box-input'

export const CLI_PATH = '/cli'
8 changes: 6 additions & 2 deletions src/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {createGlobalStyle} from 'styled-components'
import Slugger from 'github-slugger'
import Header from './components/header'
import Sidebar from './components/sidebar'
import {SkipLink} from './components/skip-nav'
import {SkipBox, SkipLink} from './components/skip-nav'
import {SKIP_TO_CONTENT_ID, SKIP_TO_SEARCH_ID} from './constants'

import {PageProvider} from './hooks/use-page'
import Layout from './layout'
Expand All @@ -27,7 +28,10 @@ const PageElement = ({element, props}) => {
return (
<BaseStyles>
<GlobalStyles />
<SkipLink />
<SkipBox>
<SkipLink href={`#${SKIP_TO_SEARCH_ID}`}>Skip to search</SkipLink>
<SkipLink href={`#${SKIP_TO_CONTENT_ID}`}>Skip to content</SkipLink>
</SkipBox>
<PageProvider value={page}>
<Box sx={{display: 'flex', flexDirection: 'column', minHeight: '100vh'}}>
<Header />
Expand Down

0 comments on commit e388aee

Please sign in to comment.