Skip to content

Commit

Permalink
feat(TabBar): accessibility improvements for TabBar & Tab (#1468)
Browse files Browse the repository at this point in the history
* feat(TabBar): accessibility improvements for TabBar & Tab

* feat: make Tabs a composite component

* fix: failing tests
  • Loading branch information
alaa-yahia authored Jul 3, 2024
1 parent 271a9dd commit b095f5a
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 150 deletions.
1 change: 1 addition & 0 deletions components/tab/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"styled-jsx": "^4"
},
"dependencies": {
"@dhis2-ui/tooltip": "^9.4.3",
"@dhis2/prop-types": "^3.1.2",
"@dhis2/ui-constants": "9.9.1",
"@dhis2/ui-icons": "9.9.1",
Expand Down
98 changes: 79 additions & 19 deletions components/tab/src/tab-bar/tabs.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,86 @@
import { colors } from '@dhis2/ui-constants'
import cx from 'classnames'
import PropTypes from 'prop-types'
import React from 'react'

const Tabs = ({ children, fixed, dataTest }) => (
<div className={cx({ fixed })} data-test={dataTest}>
{children}

<style jsx>{`
div {
display: flex;
align-items: flex-start;
position: relative;
overflow: hidden;
box-shadow: inset 0 -1px 0 0 ${colors.grey400};
flex-wrap: nowrap;
flex-grow: 1;
background: ${colors.white};
import React, { useRef, useMemo } from 'react'

const Tabs = ({ children, fixed, dataTest }) => {
const tabContainer = useRef(null)

const childrenRefs = useMemo(
() => React.Children.map(children, () => React.createRef()),
[children]
)

const handleKeyDown = (event) => {
const currentFocus = document.activeElement

if (tabContainer.current && tabContainer.current === currentFocus) {
if (childrenRefs.length > 0 && childrenRefs[0].current) {
childrenRefs[0].current.focus()
}
`}</style>
</div>
)
return
}

const currentIndex = childrenRefs.findIndex(
(ref) => ref.current === currentFocus
)

if (currentIndex === -1) {
return
}

if (event.key === 'ArrowRight') {
event.preventDefault()
const nextIndex = (currentIndex + 1) % childrenRefs.length
childrenRefs[nextIndex].current.focus()
}

if (event.key === 'ArrowLeft') {
event.preventDefault()
const prevIndex =
(currentIndex - 1 + childrenRefs.length) % childrenRefs.length
childrenRefs[prevIndex].current.focus()
}
}

return (
<div
className={cx({ fixed })}
ref={tabContainer}
data-test={dataTest}
role="tablist"
tabIndex={0}
onKeyDown={handleKeyDown}
>
{React.Children.map(children, (child, index) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, {
ref: childrenRefs[index],
})
}
// Wrap non-element children e.g string in a <span>
return (
<span ref={childrenRefs[index]} tabIndex={-1}>
{child}
</span>
)
})}

<style jsx>{`
div {
display: flex;
align-items: flex-start;
position: relative;
overflow: hidden;
box-shadow: inset 0 -1px 0 0 ${colors.grey400};
flex-wrap: nowrap;
flex-grow: 1;
background: ${colors.white};
}
`}</style>
</div>
)
}

Tabs.propTypes = {
dataTest: PropTypes.string.isRequired,
Expand Down
Loading

0 comments on commit b095f5a

Please sign in to comment.