Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom function components and TypeScript #333

Closed
anto66r opened this issue Jul 7, 2020 · 5 comments · Fixed by #469
Closed

Custom function components and TypeScript #333

anto66r opened this issue Jul 7, 2020 · 5 comments · Fixed by #469
Labels

Comments

@anto66r
Copy link

anto66r commented Jul 7, 2020

Hi everyone, I'm having an issue using custom Functional components and TypeScript. The code below won't render the TabPanels, but the Tabs are shown.

import React, { FunctionComponent, ReactElement } from 'react';
import {
  Tabs, TabList, TabPanel, Tab,
} from 'react-tabs';

interface TabsProps {
  panels: {
    title: string;
    panelContent?: ReactElement;
  }[];
}

const CustomTabPanel: FunctionComponent = ({ children }) => (
  <TabPanel>
    {children}
  </TabPanel>
);

const MyTabs: FunctionComponent<TabsProps> = (props: TabsProps) => {
  const {
    panels,
  } = props;

  return (
    <Tabs>
      <TabList>
        {panels.map(({ title }) => <Tab title={title} key={title} />)}
      </TabList>
      {
        panels.map(({ panelContent, title }) => <CustomTabPanel key={title}>{panelContent}</CustomTabPanel>)
      }
    </Tabs>
  );
};

export default MyTabs;

I'm trying to apply this, but I'm not sure how that fits in with my code. Can somebody help?

@joepvl
Copy link
Collaborator

joepvl commented Jul 8, 2020

I made a codesandbox that "fixes" your issue: https://codesandbox.io/s/naughty-vaughan-iplny

The differences are as follows:

-import React, { FunctionComponent, ReactElement } from "react";
+import React, { FunctionComponent, ReactNode } from "react";
 import { Tabs, TabList, TabPanel, Tab } from "react-tabs";
 
 interface TabsProps {
   panels: {
     title: string;
-    panelContent?: ReactElement;
+    panelContent?: ReactNode;
   }[];
 }
 
-const CustomTabPanel: FunctionComponent = ({ children }) => (
-  <TabPanel>{children}</TabPanel>
+const CustomTabPanel: FunctionComponent = ({ children, ...otherProps }) => (
+  <TabPanel {...otherProps}>{children}</TabPanel>
 );
+// @ts-ignore
+CustomTabPanel.tabsRole = "TabPanel";
 
 const MyTabs: FunctionComponent<TabsProps> = (props: TabsProps) => {
   const { panels } = props;
 
   return (
     <Tabs>
       <TabList>
         {panels.map(({ title }) => (
-          <Tab title={title} key={title} />
+          <Tab key={title}>{title}</Tab>
         ))}
       </TabList>
       {panels.map(({ panelContent, title }) => (
         <CustomTabPanel key={title}>{panelContent}</CustomTabPanel>
       ))}
     </Tabs>
   );
 };
 
 export default MyTabs;

I put "fixes" between quotes because I didn't find a great way to add tabsRole to the FunctionComponent without adding the // @ts-ignore. It works this way, but it's not exactly a great solution. Other than that, the only reasons it wasn't working were you need to pass any extra props through to TabPanel (the {... otherProps} bit), and Tab uses children for content, the title attribute would just be passed to the underlying li I think (or perhaps it is ignored entirely, not sure).

BTW the only reason I substituted ReactElement with ReactNode is I wanted to be able to specify strings as the panelContent for the example's sake. That's just a personal preference and has no influence on the functionality.

@anto66r
Copy link
Author

anto66r commented Jul 9, 2020

Thanks for your answer! I will try it out in a bit. Really weird how we have to // @ts-ignore that line... I would think there was a better way.

@frankie303
Copy link

Thanks for your answer! I will try it out in a bit. Really weird how we have to // @ts-ignore that line... I would think there was a better way.

@anto66r have you found a better way to handle this problem?

@danez
Copy link
Collaborator

danez commented Apr 17, 2022

There is now a custom type for functional components, see the example in the Readme: https://github.com/reactjs/react-tabs#pass-through-properties

@github-actions
Copy link

🎉 This issue has been resolved in version 5.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 18, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants