Whilst looking for an example of some Tab components online for a react project I came across exactly what I needed on a github repo by Diego Castillo.
However, I was using a Typescript project and, as I couldn't find anything else specific to Typescript I decided to alter Diego's code to make it work for my project (and hopefully save anyone else the work of doing the same).
Here's what they look like after some simple styling:
The files can be found on here on github, a demo has been created which you can download and run using node and webpack, but if you just want to drop in the components the two necessary files are Tab.tsx and Tabs.tsx, which can then be used by doing:
Tabs.tsx
import * as React from 'react';
/*
Credit https://gist.github.com/diegocasmo/5cd978e9c5695aefca0c6a8a19fa4c69 for original
js files, edited by Robert McDonnell to convert to typescript
*/
export default class Tabs extends React.Component<any, any> {
constructor(props: any, context: any) {
super(props, context);
this.state = {
activeTabIndex: 0,
};
this.handleTabClick = this.handleTabClick.bind(this);
}
handleTabClick(tabIndex: number) {
this.setState({
activeTabIndex: tabIndex === this.state.activeTabIndex ? this.state.activeTabIndex : tabIndex
});
}
// Encapsulate <Tabs/> component API as props for <Tab/> children
renderChildrenWithTabsApiAsProps() {
return React.Children.map(this.props.children, (child: any, index) => {
return React.cloneElement(child, {
onClick : this.handleTabClick,
tabIndex: index,
isActive: index === this.state.activeTabIndex
});
});
}
// Render current active tab content
renderActiveTabContent() {
if (this.state.activeTabIndex !== undefined) {
const {children} = this.props;
const {activeTabIndex} = this.state;
if (children != null) {
if (children[activeTabIndex]) {
return children[activeTabIndex].props.children;
}
} else {
console.dir('Error! This tab has no children!');
}
}
}
render() {
return (
<div className="tabs">
<ul className="tabs-nav nav navbar-nav navbar-offices">
{this.renderChildrenWithTabsApiAsProps()}
</ul>
<div className="tabs-active-content">
{this.renderActiveTabContent()}
</div>
</div>
);
}
}
Tab.tsx
import * as React from 'react';
/*
Credit https://gist.github.com/diegocasmo/5cd978e9c5695aefca0c6a8a19fa4c69 for original
js files, edited by Robert McDonnell to convert to typescript
*/
export interface Props {
onClick ?: Function;
tabIndex ?: Number;
isActive ?: Boolean;
iconClassName: String;
linkClassName: String;
}
function Tab ({
onClick = function(){return; },
tabIndex = '',
isActive = '',
iconClassName = '',
linkClassName = ''
}: Props) {
return (
<li className="tab">
<a
className={`tab-link ${linkClassName} ${isActive ? 'active' : ''}`}
onClick={(event) => {
event.preventDefault();
onClick(tabIndex);
}}
>
{linkClassName}
<i className={`tab-icon ${iconClassName}`}/>
</a>
</li>
);
}
export default Tab;
TabDemo.tsx
<Tabs>
<Tab iconClassName="" linkClassName="Tab1">
<h3>Elastacloud is great</h3>
</Tab>
<Tab iconClassName="" linkClassName="Tab2">
<p>
<a href="https://www.elastacloud.com" target="_blank">
Check out the website
</a>
</p>
</Tab>
<Tab iconClassName="" linkClassName="Tab3">
<p>Seriously, they also have some amazing blog posts</p>
<p>
<a href="http://channels.elastacloud.com" target="_blank">
You should check those out too
</a>
</p>
</Tab>
</Tabs>
Feel free to check it out and let me know your thoughts!