skip to Main Content

I am trying to create Tabs and have JSX Components dynamically placed into each Tab as content. I am using React and Polaris as I am creating a new Shopify App.

I cannot seem to work out how to do this – I am very new to Javascript/Typescript and even React.

I have all the Tabs working showing the correct details in each, but I cannot pull the child JSX ‘DesignForm’ and make it show as within the First Tab.

import React, { Children } from "react";
import { Card, Page, Layout, TextContainer, Image, Stack, Link, Heading, Tabs} from "@shopify/polaris";
import {ReactNode, useState, useCallback} from 'react';
import { DesignForm } from "../designform/DesignForm";

export function NavTabs() {
  const [selected, setSelected] = useState(0);
  
  interface childrenProps {
    children: JSX.Element;
  }

  const index = ({ children }: childrenProps) => {
    return (
        <>
            <DesignForm />
            {children}
        </>
    );
  };
  
  const handleTabChange = useCallback(
    (selectedTabIndex) => setSelected(selectedTabIndex),
    [],
  );

  const tabs = [
    {
      id: 'all-customers-4',
      content: 'All',
      accessibilityLabel: 'All customers',
      panelID: 'all-customers-content-4',
      children: DesignForm,
    },
    {
      id: 'accepts-marketing-4',
      content: 'Accepts marketing',
      panelID: 'accepts-marketing-content-4',
    },
    {
      id: 'repeat-customers-4',
      content: 'Repeat customers',
      panelID: 'repeat-customers-content-4',
    },
    {
      id: 'prospects-4',
      content: 'Prospects',
      panelID: 'prospects-content-4',
    },
  ];

  return (
    <Card>
      <Tabs
        tabs={tabs}
        selected={selected}
        onSelect={handleTabChange}
        disclosureText="More views"
      >
        <Card.Section title={tabs[selected].content}>
          <p>Tab {selected} selected</p>
        </Card.Section>
        <Card.Section children={tabs[selected].children}></Card.Section>
      </Tabs>
    </Card>
  );
}

2

Answers


  1. in

    {
          id: 'all-customers-4',
          content: 'All',
          accessibilityLabel: 'All customers',
          panelID: 'all-customers-content-4',
          children: DesignForm,
        }
    

    Your children (i.e DesignForm) is a function here you should set the children to your component instead

    {
          id: 'all-customers-4',
          content: 'All',
          accessibilityLabel: 'All customers',
          panelID: 'all-customers-content-4',
          children: <DesignForm/>,
        }
    

    You also could replace

    <Card.Section children={tabs[selected].children}></Card.Section>
    

    by

    <Card.Section>
    {tabs[selected].children}
    </Card.Section>
    
    Login or Signup to reply.
  2. Few pointers

    Move this outside of the component for performance reasons, and React components should start with Capital letter
    interface childrenProps {
    children: JSX.Element;
    }

      //  change from index to Index
      const Index = ({ children }: childrenProps) => {
        return (
            <>
                <DesignForm />
                {children}
            </>
        );
      };
    

    If this is static move it outside the component, as it will be recreated in every render

     const tabs = [
        {
          id: 'all-customers-4',
          content: 'All',
          accessibilityLabel: 'All customers',
          panelID: 'all-customers-content-4',
        },
        {
          id: 'accepts-marketing-4',
          content: 'Accepts marketing',
          panelID: 'accepts-marketing-content-4',
        },
        {
          id: 'repeat-customers-4',
          content: 'Repeat customers',
          panelID: 'repeat-customers-content-4',
        },
        {
          id: 'prospects-4',
          content: 'Prospects',
          panelID: 'prospects-content-4',
        },
      ]; 
    

    Create a component map, or something similar to this

    const componentMap = {
      ['all-customers-4']: DesignForm,
      // ... more components can be added in the future
    }
    
    const EmptyComponent = () => null;
    
    export function NavTabs() {
    
      const [selected, setSelected] = useState(0);
      
      const handleTabChange = useCallback(
        (selectedTabIndex) => setSelected(selectedTabIndex),
        [],
      );
    
      const ChildComponent = useMemo(() => {
    
         return componentMap[selected] ?? EmptyComponent
    
      }, [selected])
     
    
      return (
        <Card>
          <Tabs
            tabs={tabs}
            selected={selected}
            onSelect={handleTabChange}
            disclosureText="More views"
          >
            <Card.Section title={tabs[selected].content}>
              <p>Tab {selected} selected</p>
              <ChildComponent />
            </Card.Section>
            <Card.Section children={tabs[selected].children}></Card.Section>
          </Tabs>
        </Card>
      );
    }
    

    Hope this helps you in some way to find a good solution

    Cheers

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search