Skip to content

Instantly share code, notes, and snippets.

@barthap
Created September 22, 2020 08:45
Show Gist options
  • Select an option

  • Save barthap/362fc5609e7dc42d8e81f7e4cff18144 to your computer and use it in GitHub Desktop.

Select an option

Save barthap/362fc5609e7dc42d8e81f7e4cff18144 to your computer and use it in GitHub Desktop.
Tabs component in React, works in mdx-js

Demo

tabs1

tabs2


Usage:

import { Tab, Tabs } from '~/components/plugins/Tabs';

// ...

<Tabs>
  <Tab label="First tab">First tab content</Tab>
  <Tab label="Second tab">Lorem ipsum</Tab>
</Tabs>

Implementation:

import { css } from 'emotion';
import React from 'react';

import * as Constants from '~/common/constants';

const STYLES_TAB_CONTAINER = css``;
const STYLES_TAB_CONTENT = css`
  padding: 10px 20px;
`;

const STYLES_TAB_LIST = css`
  border-bottom: 1px solid #ccc;
  padding-left: 0;
`;

const STYLES_TAB_LIST_ITEM = css`
  display: inline-block;
  list-style: none;
  margin-bottom: -1px;
  padding: 10px 15px;
  font-family: ${Constants.fontFamilies.demi};
  :hover {
    cursor: pointer;
  }
`;

const STYLES_TAB_LIST_ACTIVE = css`
  background-color: white;
  border: solid #ccc;
  border-bottom: 0px;
  border-width: 1px 1px 0 1px;
  background: ${Constants.expoColors.gray[200]};
  border-radius: 4px;
`;

const TabButton = ({ activeTab, label, onClick }) => {
  const handleClick = () => onClick(label);

  const classNames = [STYLES_TAB_LIST_ITEM];
  if (activeTab === label) {
    classNames.push(STYLES_TAB_LIST_ACTIVE);
  }

  return (
    <li className={classNames.join(' ')} onClick={handleClick}>
      {label}
    </li>
  );
};

/**
 * Dummy emelent, needed for `<Tabs/>` component to work properly
 */
export const Tab = ({ children }) => children;

/**
 * @example
 * <Tabs>
 *   <Tab label="Tab1">Tab 1 content...</Tab>
 *   <Tab label="Tab2">Tab 2 content...</Tab>
 * </Tabs>
 */
export const Tabs = ({ children }) => {
  const [activeTab, setActiveTab] = React.useState(children[0].props.label);

  return (
    <div className={STYLES_TAB_CONTAINER}>
      <ol className={STYLES_TAB_LIST}>
        {children.map(child => {
          const { label } = child.props;
          return (
            <TabButton activeTab={activeTab} key={label} label={label} onClick={setActiveTab} />
          );
        })}
      </ol>
      <div className={STYLES_TAB_CONTENT}>
        {children.map(child => {
          if (child.props.label !== activeTab) {
            return;
          }
          return child.props.children;
        })}
      </div>
    </div>
  );
};
@barthap
Copy link
Author

barthap commented Mar 29, 2025

@barthap Hey, love your implementation. I edited a version of it using tailwind.

Haha, thank you. My gist is really old, I even forgot it existed 😅 I'm glad you found it helpful and thanks for sharing Tailwind version

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment