A dead simple tab component for ReactJS.
Yarn or npm:
$ yarn add react-tabify
$ npm install --save react-tabify
import { Tab, Tabs } from 'react-tabify';
export default () => (
<Tabs>
<Tab label="Tab 1">First Content</Tab>
<Tab label="Tab 2">Second Content</Tab>
<Tab label="Tab 3">Third Content</Tab>
</Tabs>
);
react-tabify
consists of two (2) components which need to be used together.
Name | Type | Default | Description |
---|---|---|---|
id |
string |
__tabify__ |
Id of the <Tabs /> component |
defaultActiveKey |
string / number |
0 |
eventKey of the initial <Tab /> to render |
activeKey |
string / number |
eventKey of the current <Tab /> |
|
theme |
object |
Optional color theme | |
stacked |
bool |
false |
Whether to display <Tabs /> vertically |
sticky |
bool |
false |
Enable sticky tabs |
onSelect |
func |
Callback fired when a <Tab /> is selected |
|
style |
object |
style forwarded to the <Tab /> containing <div /> |
|
children |
node |
<Tab /> components |
Name | Type | Default | Description |
---|---|---|---|
eventKey |
string / number |
index |
Unique key of the <Tab /> |
label |
string / node |
Label of the <Tab/> |
|
hide |
bool |
false | Whether to hide the <Tab/> |
style |
object |
style forwarded to the <Tab /> containing <div /> |
|
children |
node |
Any abritary React node |
By default, <Tabs />
are uncontrolled, and will display the first <Tab />
child during initial render. Use defaultActiveKey
to default to another <Tab />
instead.
If <Tab />
components are not passed an eventKey
, they will default to their order index. In the example below, we're defaulting <Tabs />
to display "Tab 3" since it sits at the second index (defaultActiveKey={2}
).
export default () => (
<Tabs defaultActiveKey={2}>
<Tab label="Tab 1">First Content</Tab>
<Tab label="Tab 2">Second Content</Tab>
<Tab label="Tab 3">Third Content</Tab>
</Tabs>
);
Alternatively, to control the component, pass an activeKey
, however you must pass an onSelect
callback to handle the event. onSelect
passes the eventKey
of the selected <Tab />
.
Again, if your <Tab />
components are not passed an eventKey
, they will default to their order index.
import { Tab, Tabs } from 'react-tabify';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
activeKey: 0
};
}
handleTabSelect = activeKey => {
this.setState({ activeKey });
};
render() {
return (
<Tabs activeKey={this.state.activeKey} onSelect={this.handleTabSelect}>
<Tab label="Tab 1">First Content</Tab>
<Tab label="Tab 2">Second Content</Tab>
<Tab label="Tab 3">Third Content</Tab>
</Tabs>
);
}
}
Add the stacked
prop to render the tabs vertically.
export default () => (
<Tabs stacked>
<Tab label="Tab 1">First Content</Tab>
<Tab label="Tab 2">Second Content</Tab>
<Tab label="Tab 3">Third Content</Tab>
</Tabs>
);
If <Tabs />
is uncontrolled, pass sticky
to "remember" the last active <Tab />
between page refreshes. When sticky
is enabled, you must pass you own id
to <Tabs />
. This will be used within LocalStorage
to distinguish between multiple <Tabs />
instances.
LocalStorage
must be enabled in the browser.
export default () => (
<Tabs sticky>
<Tab label="Tab 1">First Content</Tab>
<Tab label="Tab 2">Second Content</Tab>
<Tab label="Tab 3">Third Content</Tab>
</Tabs>
);
Easily nest tabs to create a section/subsection layout.
export default () => (
<Tabs stacked>
<Tab label="Tab 1">
<Tabs>
<Tab label="Subtab 1.1">Tab 1 Content 1</Tab>
<Tab label="Subtab 1.2">Tab 1 Content 2</Tab>
<Tab label="Subtab 1.3">Tab 1 Content 3</Tab>
</Tabs>
</Tab>
<Tab label="Tab 2">
<Tabs>
<Tab label="Subtab 2.1">Tab 2 Content 1</Tab>
<Tab label="Subtab 2.2">Tab 2 Content 2</Tab>
<Tab label="Subtab 2.3">Tab 2 Content 3</Tab>
</Tabs>
</Tab>
<Tab label="Tab 3">
<Tabs>
<Tab label="Subtab 3.1">Tab 3 Content 1</Tab>
<Tab label="Subtab 3.2">Tab 3 Content 2</Tab>
<Tab label="Subtab 3.3">Tab 3 Content 3</Tab>
</Tabs>
</Tab>
</Tabs>
);
To ensure that scrolling (i.e. overflow
) is only visible within the <Tab />
component, we'll want to wrap <Tabs />
with a Flexbox whose height is set to 100%
. Otherwise, if our <Tab />
had enough content to induce a scrollbar, our entire <Tabs />
component would be subject to scrolling, which means the clickable tab links (horizontal and stacked) could scroll out of view.
const tabsContainer = {
display: "flex",
height: "100%"
};
const App = () => (
<div style={tabsContainer}>
<Tabs stacked>
<Tab label="Tab 1" style={tabStyle}>
{__getLorumIpsum()}
</Tab>
<Tab label="Tab 2" style={tabStyle}>
{__getLorumIpsum()}
</Tab>
<Tab label="Tab 3" style={tabStyle}>
{__getLorumIpsum()}
</Tab>
</Tabs>
</div>
);
Use the hide
prop to dynmically hide/show <Tab />
components. Pass a bool
, or evaluate a function that returns a bool
.
// Dummy rejection
const __hasAccess = user => false;
const App = ({ user }) => (
<div style={styles}>
<Tabs>
<Tab label="Super Admin Tab" hide>
Super Admin Content
</Tab>
<Tab label="Admin Tab" hide={() => !__hasAccess(user)}>
Admin Content
</Tab>
<Tab label="User Tab">User Content</Tab>
</Tabs>
</div>
);
react-tabify
leverages <ThemeManager />
from glamorous to expose an optional theme
object. The tabs
property of the theme
controls the horizontal styling, while menu
controls the stacked view.
Accepts any valid color (e.g. "red", "#FF0000", "hsl(0, 100%, 50%)", "rgb(255, 0, 0)", etc).
const theme = {
tabs: {
color: <color>,
borderBottomColor: <color>,
active: {
borderBottomColor: <color>,
color: <color>
},
hover: {
borderBottomColor: <color>,
color: <color>
}
},
menu: {
color: <color>,
borderRight: <color>,
active: {
backgroundColor: <color>,
color: <color>
},
hover: {
color: <color>,
backgroundColor: <color>
}
}
};
Override any of the properties above. Here's a simple example:
const theme = {
tabs: {
color: "red",
active: {
color: "green"
}
}
}
const App = () => (
<Tabs theme={theme}>
<Tab label="Tab 1">First Content</Tab>
<Tab label="Tab 2">Second Content</Tab>
<Tab label="Tab 3">Third Content</Tab>
</Tabs>
);
A more complex, yet very ugly example theme:
const theme = {
tabs: {
color: "#FF000",
active: {
color: "green"
}
},
menu: {
color: "hsl(248, 39%, 39%)",
borderRight: "darkmagenta",
active: {
backgroundColor: "rgb(165,42,42)"
},
hover: {
color: "hsl(240, 100%, 50%)"
}
}
};
const App = () => (
<Tabs stacked theme={theme}>
<Tab label="Tab 1">
<Tabs theme={theme}>
<Tab label="Subtab 1.1">Tab 1 Content 1</Tab>
<Tab label="Subtab 1.2">Tab 1 Content 2</Tab>
<Tab label="Subtab 1.3">Tab 1 Content 3</Tab>
</Tabs>
</Tab>
<Tab label="Tab 2">
<Tabs theme={theme}>
<Tab label="Subtab 2.1">Tab 2 Content 1</Tab>
<Tab label="Subtab 2.2">Tab 2 Content 2</Tab>
<Tab label="Subtab 2.3">Tab 2 Content 3</Tab>
</Tabs>
</Tab>
<Tab label="Tab 3">
<Tabs theme={theme}>
<Tab label="Subtab 3.1">Tab 3 Content 1</Tab>
<Tab label="Subtab 3.2">Tab 3 Content 2</Tab>
<Tab label="Subtab 3.3">Tab 3 Content 3</Tab>
</Tabs>
</Tab>
</Tabs>
);