mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-04 04:37:28 +02:00
refactor(v2): make better a11y for tabs (#1990)
* refactor(v2): make better a11y for tabs * Update styles.module.css
This commit is contained in:
parent
3aa2ab6ab3
commit
3265dda895
2 changed files with 61 additions and 2 deletions
|
@ -9,28 +9,77 @@ import React, {useState, Children} from 'react';
|
||||||
|
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
|
const keys = {
|
||||||
|
left: 37,
|
||||||
|
right: 39,
|
||||||
|
};
|
||||||
|
|
||||||
function Tabs(props) {
|
function Tabs(props) {
|
||||||
const {block, children, defaultValue, values} = props;
|
const {block, children, defaultValue, values} = props;
|
||||||
const [selectedValue, setSelectedValue] = useState(defaultValue);
|
const [selectedValue, setSelectedValue] = useState(defaultValue);
|
||||||
|
const tabRefs = [];
|
||||||
|
|
||||||
|
const focusNextTab = (tabs, target) => {
|
||||||
|
const next = tabs.indexOf(target) + 1;
|
||||||
|
|
||||||
|
if (!tabs[next]) {
|
||||||
|
tabs[0].focus();
|
||||||
|
} else {
|
||||||
|
tabs[next].focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const focusPreviousTab = (tabs, target) => {
|
||||||
|
const prev = tabs.indexOf(target) - 1;
|
||||||
|
|
||||||
|
if (!tabs[prev]) {
|
||||||
|
tabs[tabs.length - 1].focus();
|
||||||
|
} else {
|
||||||
|
tabs[prev].focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeydown = (tabs, target, event) => {
|
||||||
|
switch (event.keyCode) {
|
||||||
|
case keys.right:
|
||||||
|
focusNextTab(tabs, target);
|
||||||
|
break;
|
||||||
|
case keys.left:
|
||||||
|
focusPreviousTab(tabs, target);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ul
|
<ul
|
||||||
|
role="tablist"
|
||||||
|
aria-orientation="horizontal"
|
||||||
className={classnames('tabs', {
|
className={classnames('tabs', {
|
||||||
'tabs--block': block,
|
'tabs--block': block,
|
||||||
})}>
|
})}>
|
||||||
{values.map(({value, label}) => (
|
{values.map(({value, label}) => (
|
||||||
<li
|
<li
|
||||||
className={classnames('tab-item', {
|
role="tab"
|
||||||
|
tabIndex="0"
|
||||||
|
aria-selected={selectedValue === value}
|
||||||
|
className={classnames('tab-item', styles.tabItem, {
|
||||||
'tab-item--active': selectedValue === value,
|
'tab-item--active': selectedValue === value,
|
||||||
})}
|
})}
|
||||||
key={value}
|
key={value}
|
||||||
|
ref={tabControl => tabRefs.push(tabControl)}
|
||||||
|
onKeyDown={event => handleKeydown(tabRefs, event.target, event)}
|
||||||
|
onFocus={() => setSelectedValue(value)}
|
||||||
onClick={() => setSelectedValue(value)}>
|
onClick={() => setSelectedValue(value)}>
|
||||||
{label}
|
{label}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
<div className="margin-vert--md">
|
<div role="tabpanel" className="margin-vert--md">
|
||||||
{
|
{
|
||||||
Children.toArray(children).filter(
|
Children.toArray(children).filter(
|
||||||
child => child.props.value === selectedValue,
|
child => child.props.value === selectedValue,
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2017-present, Facebook, Inc.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.tabItem:focus {
|
||||||
|
background-color: var(--ifm-hover-overlay);
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue