React | Multi Tab Component (Animated)

 <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.6/css/all.css">
 <link rel="stylesheet" href="https://codepen.io/TheVVaFFle/pen/JpWrWw.css">
 <link href='https://fonts.googleapis.com/css?family=Roboto:100,300,400,700' rel='stylesheet' type='text/css'>


  <div id="root"></div>


  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.development.js"   ></script> 
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.development.js"></script>
html, body, #root, #app {
	height: 100%;
	margin: 0px;
	padding: 0px;
	width: 100%;
  }
  
  body {
	overflow-x: hidden;
  }
  
  #app div, #app h1, #app h2, #app h3, #app h4, #app h5, #app h6, #app input, #app button, #app li {
	font-family: "Roboto", sans-serif;
  }
  #app #app-content {
	left: 50%;
	position: absolute;
	top: 50%;
	transform: translateX(-50%) translateY(-50%);
  }
  #app #app-content .my-tab-content {
	height: 300px;
  }
  #app #app-content .my-tab-content .tab-icon {
	left: 50%;
	position: absolute;
	top: 50%;
	transform: translateX(-50%) translateY(-50%);
  }
  #app #app-content .my-tab-content .tab-icon i {
	color: #f0f0f0;
	font-size: 10em;
  }
  #app #app-content .my-tab-content .tab-icon h1 {
	color: #c8c8c8;
	font-size: 0.9em;
	font-weight: 100;
	margin: 0px;
	margin-top: 10px;
	text-align: center;
  }
class Tabs extends React.PureComponent {
  constructor(props) {
    super(props);
    this.getTabSize = this.getTabSize.bind(this);
    this.getColors = this.getColors.bind(this);
    this.getTabs = this.getTabs.bind(this);
    this.getTabOptions = this.getTabOptions.bind(this);
    this.setSelectedTab = this.setSelectedTab.bind(this);
    this.createTabOptions = this.createTabOptions.bind(this);
    this.updateTabBarStyles = this.updateTabBarStyles.bind(this);
    this.state = {
      selectedTab: 0,
      transitionDuration: 400,
      isTransitioning: false,
      tabBarStyles: {} };
  }
  componentDidMount() {
    const { selectedTab, transitionDuration } = this.state;
    const tabWidth = this.getTabSize().width,
    options = this.getTabOptions(),
    tabOptionWidth = tabWidth / options.length,
    left = `${tabOptionWidth * selectedTab}px`,
    right = `${tabWidth - tabOptionWidth * (selectedTab + 1)}px`,
    transition = `left ${transitionDuration}ms, right ${transitionDuration}ms, width ${transitionDuration / 2}ms`,
    accentColor = this.getColors().accent;
    this.updateTabBarStyles(left, right, transition, accentColor);

    //Added later for initial animation purposes
    if (this.props.initialTab) {
      setTimeout(() => this.setSelectedTab(this.props.initialTab), 250);
    }
  }
  componentDidUpdate(prevProps, prevState) {
    if (prevState.selectedTab !== this.state.selectedTab) {
      const { selectedTab, transitionDuration, tabBarStyles } = this.state;
      const tabWidth = this.getTabSize().width,
      options = this.getTabOptions(),
      tabOptionWidth = tabWidth / options.length,
      direction = prevState.selectedTab < selectedTab ? 1 : -1,
      left = direction === -1 ? `${tabOptionWidth * selectedTab + tabOptionWidth / 2}px` : null,
      right = direction === 1 ? `${tabWidth - tabOptionWidth * (selectedTab + 1) + tabOptionWidth / 2}px` : null,
      nextLeft = `${tabOptionWidth * selectedTab}px`,
      nextRight = `${tabWidth - tabOptionWidth * (selectedTab + 1)}px`;
      this.setState({ isTransitioning: true });
      this.updateTabBarStyles(left, right, null, null);
      setTimeout(() => this.updateTabBarStyles(nextLeft, nextRight, null, null), transitionDuration / 2);
      setTimeout(() => this.setState({ isTransitioning: false }), transitionDuration);
    }
  }
  getTabSize() {
    const { tabHeight, tabWidth } = this.props;
    return {
      height: tabHeight || 300,
      width: tabWidth || 450 };

  }
  getColors() {
    const { accentColor, backgroundColor } = this.props;
    return {
      accent: accentColor || '#03a9f4',
      background: backgroundColor || 'white' };

  }
  setSelectedTab(index) {
    index = Math.max(0, index);
    index = Math.min(index, this.props.children.length - 1);
    this.setState({ selectedTab: index });
  }
  getTabs() {
    const { children } = this.props;
    const { transitionDuration } = this.state;
    const tabSize = this.getTabSize(),
    moreProps = {
      width: `${tabSize.width}px`,
      transition: `opacity ${transitionDuration * 1.5}ms, transform ${transitionDuration / 2}ms` };

    let tabs = !children ? new Array( /*#__PURE__*/React.createElement(Tab, { key: 0, label: 'Default' })) :
    children.length ? children : new Array(children);
    return tabs.map(tab => ({ ...tab, props: { ...tab.props, ...moreProps } }));
  }
  getTabOptions() {
    const { children } = this.props;
    let tabOptions = null;
    if (!children) {
      tabOptions = new Array( /*#__PURE__*/React.createElement(Tab, { key: 0, label: 'Default' }));
    } else
    {
      tabOptions = children.length ? children : new Array(children);
    }
    return tabOptions.map(tab => tab.props.label);
  }
  createTabOptions() {
    const { selectedTab } = this.state;
    const tabWidth = this.getTabSize().width,
    options = this.getTabOptions(),
    tabOptionWidth = tabWidth / options.length;
    return options.map((tab, index) => {
      const selected = selectedTab === index,
      textStyle = selected ? { color: this.getColors().accent } : {},
      classes = `tab-option ${selected ? 'selected' : ''}`;
      return /*#__PURE__*/(
        React.createElement("div", {
          key: index,
          className: classes,
          style: { width: `${tabOptionWidth}px` },
          onClick: () => this.setSelectedTab(index) }, /*#__PURE__*/

        React.createElement("h1", { style: textStyle }, tab)));
    });
  }
  updateTabBarStyles(left, right, transition, backgroundColor) {
    const { tabBarStyles } = this.state;
    this.setState({
      tabBarStyles: {
        left: left || tabBarStyles.left,
        right: right || tabBarStyles.right,
        transition: transition || tabBarStyles.transition,
        backgroundColor: backgroundColor || tabBarStyles.backgroundColor } });
  }
  render() {
    const { customClass } = this.props;
    const { tabBarStyles, selectedTab, transitionDuration, isTransitioning } = this.state;
    const tabSize = this.getTabSize(),
    colors = this.getColors(),
    options = this.getTabOptions(),
    tabWrapperClasses = `tab-wrapper ${isTransitioning ? 'transitioning' : ''} ${customClass ? customClass : ''}`,
    tabWrapperStyles = { backgroundColor: colors.background, width: `${tabSize.width}px` },
    tabsStyles = {
      height: `${tabSize.height}px`,
      width: `${tabSize.width * options.length}px`,
      transform: `translateX(${-1 * selectedTab * tabSize.width}px)`,
      transition: `transform ${transitionDuration}ms` },

    tabs = this.getTabs();

    return /*#__PURE__*/(
      React.createElement("div", { className: tabWrapperClasses, style: tabWrapperStyles }, /*#__PURE__*/
      React.createElement("div", { className: "tab-selection" }, /*#__PURE__*/
      React.createElement("div", { className: "tab-options" },
      this.createTabOptions()), /*#__PURE__*/

      React.createElement("div", { className: "tab-selection-bar-track" }, /*#__PURE__*/
      React.createElement("div", {
        className: "tab-selection-bar",
        style: tabBarStyles }))), /*#__PURE__*/
		React.createElement("div", { className: "tabs", style: tabsStyles },
      tabs)));
}}

class Tab extends React.Component {
  render() {
    const { children, width, transition, customClass } = this.props;
    const tabClasses = `tab ${customClass ? customClass : ''}`,
    tabStyles = { width, transition },
    tabContentStyles = { transition };
    return /*#__PURE__*/(
      React.createElement("div", { className: tabClasses, style: tabStyles }, /*#__PURE__*/
      React.createElement("div", { className: "tab-contents", style: tabContentStyles },
      children)));
}}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      accentColor: '#03a9f4',
      backgroundColor: '#fff' };

  }
  getTabs() {
    return [
    { label: 'Home', icon: 'fas fa-home' },
    { label: 'Trending', icon: 'fas fa-fire' },
    { label: 'Inbox', icon: 'fas fa-inbox' },
    { label: 'Profile', icon: 'far fa-user-circle' }].
    map((tab, index) => /*#__PURE__*/
    React.createElement(Tab, { key: index, customClass: 'my-custom-tab-class', label: tab.label }, /*#__PURE__*/
    React.createElement("div", { className: "my-tab-content" }, /*#__PURE__*/
    React.createElement("div", { className: "tab-icon" }, /*#__PURE__*/
    React.createElement("i", { className: tab.icon }), /*#__PURE__*/
    React.createElement("h1", null, "The ", tab.label, " Tab")))));
}
  render() {
    const { accentColor, backgroundColor } = this.state;
    const tabs = this.getTabs();

    return /*#__PURE__*/(
      React.createElement("div", { id: "app", style: { backgroundColor: accentColor } }, /*#__PURE__*/
      React.createElement("div", { id: "app-content" }, /*#__PURE__*/
      React.createElement(Tabs, {
        customClass: 'my-custom-tab-wrapper-class',
        tabHeight: 300,
        tabWidth: 500,
        backgroundColor: backgroundColor,
        accentColor: accentColor,
        initialTab: 2 },
      tabs))));
  }}


ReactDOM.render( /*#__PURE__*/React.createElement(App, null), document.getElementById('root'));