Skip to content

Instantly share code, notes, and snippets.

@ahomu
Last active August 8, 2016 10:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ahomu/3c4b0c53250147cc3d8dc766b08d4be3 to your computer and use it in GitHub Desktop.
Save ahomu/3c4b0c53250147cc3d8dc766b08d4be3 to your computer and use it in GitHub Desktop.
const KEYCODE_LEFT = 37;
const KEYCODE_RIGHT = 39;
class TabList extends React.Component {
static propTypes = {
children : React.PropTypes.node,
selectedIndex : React.PropTypes.number,
onChangeSelected: React.PropTypes.func
};
onClickTab(i) {
this.props.onChangeSelected(i);
}
onMoveFocus(e) {
const { selectedIndex } = this.props;
let nextIndex;
switch(e.keyCode) {
case KEYCODE_LEFT:
if (selectedIndex !== 0) {
nextIndex = selectedIndex - 1;
this.props.onChangeSelected(nextIndex);
}
break;
case KEYCODE_RIGHT:
if (selectedIndex !== this.props.children.length - 1) {
nextIndex = selectedIndex + 1;
this.props.onChangeSelected(nextIndex);
}
break;
}
if (nextIndex != null) {
this.refs[`tab${nextIndex}`].setFocus();
}
}
render() {
const { selectedIndex, onClickTab, onMoveFocus } = this.props;
return (
<ul role="tablist">
{this.props.children.map((child, i) => {
return React.cloneElement(child, {
ref : `tab${i}`,
selected : selectedIndex === i,
onClickTab : this.onClickTab.bind(this, i),
onMoveFocus: this.onMoveFocus.bind(this)
});
})}
</ul>
);
}
}
class Tab extends React.Component {
static propTypes = {
controlsFor: React.PropTypes.string,
children : React.PropTypes.node,
selected : React.PropTypes.bool,
onMoveFocus: React.PropTypes.func,
onClickTab : React.PropTypes.func
};
setFocus() {
this.refs.tab.focus();
}
render() {
const { selected, controlsFor } = this.props;
return (
<li role="presentation">
<button
ref="tab"
role="tab"
tabIndex={selected ? '0' : '-1'}
aria-selected={selected ? 'true' : 'false'}
aria-controls={controlsFor}
onKeyUp={this.props.onMoveFocus}
onClick={this.props.onClickTab}>
{this.props.children}
</button>
</li>
);
}
}
class TabPanel extends React.Component {
static propTypes = {
id : React.PropTypes.string,
selected: React.PropTypes.bool
};
static defaultProps = {
selected: false
};
render() {
const { id, selected } = this.props;
return (
<div role="tabpanel" id={id} aria-hidden={selected ? 'false' : 'true'}>
{this.props.children}
</div>
);
}
}
class Container extends React.Component {
state = {
selectedIndex: 0
};
onChangeSelected(index) {
this.setState({
selectedIndex: index
});
}
render() {
const { selectedIndex } = this.state;
return (
<div>
<TabList
selectedIndex={selectedIndex}
onChangeSelected={this.onChangeSelected.bind(this)}>
<Tab controlsFor="foo">1st Panel</Tab>
<Tab controlsFor="bar">2nd Panel</Tab>
<Tab controlsFor="baz">3rd Panale</Tab>
</TabList>
<TabPanel id="foo" selected={selectedIndex === 0}>
<h2>1st Panel</h2>
<ul>
<li><a href="http://example.com" target="_blank">example.com</a></li>
<li><a href="http://example.com" target="_blank">example.com</a></li>
<li><a href="http://example.com" target="_blank">example.com</a></li>
</ul>
</TabPanel>
<TabPanel id="bar" selected={selectedIndex === 1}>
<h2>2nd Panel</h2>
<ul>
<li><a href="http://example.com" target="_blank">example.com</a></li>
<li><a href="http://example.com" target="_blank">example.com</a></li>
<li><a href="http://example.com" target="_blank">example.com</a></li>
</ul>
</TabPanel>
<TabPanel id="baz" selected={selectedIndex === 2}>
<h2>3rd Panel</h2>
<ul>
<li><a href="http://example.com" target="_blank">example.com</a></li>
<li><a href="http://example.com" target="_blank">example.com</a></li>
<li><a href="http://example.com" target="_blank">example.com</a></li>
</ul>
</TabPanel>
</div>
);
}
}
ReactDOM.render(<Container />, document.getElementById('example'));
<div data-reactroot="">
<ul role="tablist">
<li role="presentation">
<button role="tab" tabindex="0" aria-selected="true" aria-controls="foo">1st Panel</button>
</li>
<li role="presentation">
<button role="tab" tabindex="-1" aria-selected="false" aria-controls="bar">2nd Panel</button>
</li>
<li role="presentation">
<button role="tab" tabindex="-1" aria-selected="false" aria-controls="baz">3rd Panale</button>
</li>
</ul>
<div role="tabpanel" id="foo" aria-hidden="false">
<h2>1st Panel</h2>
<ul>
<li><a href="http://example.com" target="_blank">example.com</a>
</li>
<li><a href="http://example.com" target="_blank">example.com</a>
</li>
<li><a href="http://example.com" target="_blank">example.com</a>
</li>
</ul>
</div>
<div role="tabpanel" id="bar" aria-hidden="true">
<h2>2nd Panel</h2>
<ul>
<li><a href="http://example.com" target="_blank">example.com</a>
</li>
<li><a href="http://example.com" target="_blank">example.com</a>
</li>
<li><a href="http://example.com" target="_blank">example.com</a>
</li>
</ul>
</div>
<div role="tabpanel" id="baz" aria-hidden="true">
<h2>3rd Panel</h2>
<ul>
<li><a href="http://example.com" target="_blank">example.com</a>
</li>
<li><a href="http://example.com" target="_blank">example.com</a>
</li>
<li><a href="http://example.com" target="_blank">example.com</a>
</li>
</ul>
</div>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment