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               | eventKeyof the initial<Tab />to render | 
| activeKey | string/number | eventKeyof 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.
LocalStoragemust 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>
);