reactjstabscomponentsantdcode-cleanup

How to apply styles to TabPane in new Antd Tabs component


This is my old implementation of the Tabs component in Ant Design.

const tabList = [
  {
    key: "tab1",
    label: "Tab1",
    children: <Tab1 />,
  },
  {
    key: "tab2",
    label: "Tab2",
    children: <Tab2 />,
  },
];

<Tabs onChange={onTabChange} activeKey={selectedTab}>
  {tabList.map((tab) => {
    const { key, label, children } = tab;
    return (
      <Tabs.TabPane
        key={key}
        tab={label}
        style={{ margin: "1.5rem auto 1.5rem" }}
      >
        {children}
      </Tabs.TabPane>
    );
  })}
</Tabs>;

In the new version ( > 4.23.0 ) the boilerplate got reduced.

I can simply pass my tabList to my Tabs as a prop items.

The new code looks something like this.

<Tabs items={tabList} />

But I had an issue with styling.

I am adding top and bottom margins to all of my TabPane components.

To get that margin in the new implementation. I had to do something like this.

  {
    key: "tab1",
    label: "Tab1",
    children: <Tab1 style={{margin: "1.5rem 0 1.5rem"}} />,
  },

Here I am facing two issues.

  1. I need to add this for all my tabs in the tabList
  2. I need to have a div in every component spreading the props that are passed above.

function Tab1(props) {
  return <div {...props}>JSX for original Tab1</div>;
}

Is there a better way to do this?


Solution

  • Higher order component can solve this issue

    Use a higher Order component like <TabPaneWrapper> or <TabChildrenWrapper>. This component does nothing but to wrap your children (<TabPane>) with a div and give the styles you require.

    Component:

    export function TabPaneWrapper({
      children,
      ...props
    }){
    
      return (
        <div style={{ margin: "1.5rem auto 1.5rem" }} {...props}>
          {children}
        </div>
      );
    }
    

    Usage:

    const tabList = [
      {
        key: "tab1",
        label: "Tab1",
        children: <TabPaneWrapper> <Tab1 /> </TabPaneWrapper>,
      },
      {
        key: "tab2",
        label: "Tab2",
        children: <TabPaneWrapper> <Tab2 /> </TabPaneWrapper>,
      },
    ];
    

    If you have more tabs or use this tabs component in multiple places. You will find TabPaneWrapper to be repetitive. In such case,

    1. You can create a custom Tabs component like <CustomTabs/> which takes the tabList mentioned in the question.
    2. Instead of wrapping every tab in the tabList with <TabPaneWrapper/>. You can loop this list inside the <CustomTabs/> component to generate the tabList mentioned above and then pass it to the Ant Desing <Tabs/> component.