Skip to content

Instantly share code, notes, and snippets.

@r2dev
Created November 26, 2018 21:58
Show Gist options
  • Save r2dev/3a21e516b8c301f2e61cd16fa51ee56c to your computer and use it in GitHub Desktop.
Save r2dev/3a21e516b8c301f2e61cd16fa51ee56c to your computer and use it in GitHub Desktop.
import React, { Component } from "react";
let keys = {
end: 35,
home: 36,
left: 37,
up: 38,
right: 39,
down: 40,
delete: 46,
enter: 13,
space: 32
};
class App extends Component {
render() {
return <Tab />;
}
}
class Tab extends Component {
state = {
active: 0
};
constructor(props) {
super(props);
this.tabRefs = [React.createRef(), React.createRef(), React.createRef()];
this.tabList = React.createRef();
}
handleKeyDown = event => {
let key = event.keyCode;
switch (key) {
case keys.end:
{
this.tabRefs[2].current.focus();
}
break;
case keys.home:
{
this.tabRefs[0].current.focus();
}
break;
case keys.down:
case keys.up:
{
this.handleArrow(event);
}
break;
default:
}
};
handleKeyUp = event => {
let key = event.keyCode;
switch (key) {
case keys.left:
case keys.right:
{
this.handleArrow(event);
}
break;
case keys.enter:
case keys.space:
{
this.setState({ active: event.target.dataset.index });
}
break;
default:
}
};
handleArrow = event => {
let key = event.keyCode;
let vertical =
this.tabList.current.getAttribute("aria-orientation") === "vertical";
let proceed = false;
if (vertical) {
if (key === keys.up || key === keys.down) {
event.preventDefault();
proceed = true;
}
} else {
if (key === keys.left || key === keys.right) {
proceed = true;
}
}
if (proceed) {
const index = parseInt(event.target.dataset.index);
if (key === keys.up || key === keys.left) {
if (index === 0) {
this.tabRefs[2].current.focus();
} else {
this.tabRefs[index - 1].current.focus();
}
} else if (key === keys.down || key === keys.right) {
if (index === 2) {
this.tabRefs[0].current.focus();
} else {
this.tabRefs[index + 1].current.focus();
}
}
}
};
handleClick = (event) => {
const index = parseInt(event.target.dataset.index);
this.setState({active: index})
}
render() {
const { active } = this.state;
return (
<div>
<div role="tablist" ref={this.tabList}>
<button
data-index={0}
role="tab"
aria-selected={active === 0}
id="a-button"
tabIndex={active === 0 ? undefined : -1}
onClick={this.handleClick}
aria-controls="a-tab"
onKeyDown={this.handleKeyDown}
onKeyUp={this.handleKeyUp}
ref={this.tabRefs[0]}
>
A
</button>
<button
data-index={1}
role="tab"
aria-selected={active === 1}
id="b-button"
tabIndex={active === 1 ? undefined : -1}
onClick={this.handleClick}
aria-controls="b-tab"
onKeyDown={this.handleKeyDown}
onKeyUp={this.handleKeyUp}
ref={this.tabRefs[1]}
>
B
</button>
<button
data-index={2}
role="tab"
aria-selected={active === 2}
id="c-button"
tabIndex={active === 2 ? undefined : -1}
onClick={this.handleClick}
aria-controls="c-tab"
onKeyDown={this.handleKeyDown}
onKeyUp={this.handleKeyUp}
ref={this.tabRefs[2]}
>
C
</button>
</div>
<div
tabIndex="0"
role="tabpanel"
hidden={active !== 0}
id="a-tab"
aria-labelledby="a-button"
>
A content
</div>
<div
tabIndex="0"
role="tabpanel"
hidden={active !== 1}
id="b-tab"
aria-labelledby="b-button"
>
B content
</div>
<div
tabIndex="0"
role="tabpanel"
hidden={active !== 2}
id="c-tab"
aria-labelledby="c-button"
>
<form>
<input type="text" />
<button>submit</button>
</form>
</div>
</div>
);
}
}
export default App;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment