3

I am trying to get my hands on compound component pattern in ReactJS. And all is good but I am not able to export the component the way I want.

I have created one basic Table (Data Grid), which has many component like header, row, column, search, pagination etc.

And I want the end user to import this Table in this way.

import Table from './Table'

const DataGrid = () => {
     return (
        <Table>
            <Table.Title></Table.Title>
            <Table.Header>
                <Table.Row></Table.Row>
            </Table.Header>
        
            <Table.Body>
                <Table.Row></Table.Row>
            </Table.Body>
        </Table>
     )
}

Now in component folder, I have one index.js file where I am trying to import all component and then trying to export it in a object

import {Table} from './Table'
import {Title} from './Title'
import {Header} from './Header'
import {Body} from './Body'

Now what should I do to export in a way I want. Tried many solutions, but nothing is working.

4
  • May you share the code for ./Table? Specifically how you are exporting it Commented May 13, 2021 at 11:20
  • export default Table; export { Title }; Commented May 13, 2021 at 11:21
  • Please edit the question rather than posting code in the comments? Also, one line is not enough, please make sure the example is a minimal reproducible example. Show, not tell Commented May 13, 2021 at 11:24
  • 1
    @evolutionxbox The reason I didn't include it in answer itself because as I said I tried many different solution already and to list all of them here won't be a better choice. And if anyone already knows what needs to be done, he can clearly tell what needs to be done for this particular situation. He doesn't need to look what I am doing wrong. (For this particular question) Commented May 13, 2021 at 11:32

2 Answers 2

5

You need to import everything in index file and prepare a new object and export it:

index.js:

import { Table } from "./Table"; // this imports from Table.jsx file
import { Title } from "./Title";
import { Body } from "./Body";
import { Header } from "./Header";
import { Row } from "./Row";

const all = Table; // <-- Here: this (all) is the new object.
// We can name it whatever we want as it is going to be a default export

all.Title = Title;
all.Body = Body;
all.Header = Header;
all.Row = Row;

export default all;

Now, you can use it like shown below:

DataGrid.jsx:

import Table from "./Table"; // this imports from index.js file under "Table" folder

const DataGrid = () => {
  return (
    <Table>
      <Table.Title></Table.Title>
      <Table.Header>
        <Table.Row></Table.Row>
      </Table.Header>

      <Table.Body>
        <Table.Row></Table.Row>
      </Table.Body>
    </Table>
  );
};

Edit:

This answer assumes that you have components under directories like below. Make sure to change the paths when importing if you have a different one.

src/
  Table/
    Body.jsx
    Header.jsx
    index.js
    Row.jsx
    Table.jsx
    Title.jsx
  DataGrid.jsx
Sign up to request clarification or add additional context in comments.

2 Comments

I swear, I tried this approach. But don't know why it didn't work that time. Now it is working. But now I am having another issue. Whichever props I am passing to any component (except Table itself), it is not being passed. Seems like I might need to use React.cloneElement to fix this issue or something else. NVM, thanks for your detailed answer.
It is working now, I was doing one silly mistake. Thanks man.
0

If the goal is to export a named compound component, it can be done like this:

const All = ({ children }: { children: ReactNode[] }) => {
  return (
    <table>
      <thead>{children[0]}</thead>
      <tbody>{children[1]}</tbody>
    </table>
  );
};

// Header row
const Thr = ({ children }: PropsWithChildren) => {
  return <tr>{children}</tr>;
};

const Tr = ({ children }: PropsWithChildren) => {
  return <tr>{children}</tr>;
};

const Th = ({ children }: PropsWithChildren) => {
  return <th>{children}</th>;
};

const Td = ({ children }: PropsWithChildren) => {
  return <td>{children}</td>;
};

All.Thr = Thr;
All.Th = Th;

All.Tr = Tr;
All.Td = Td;

export const Table = All;

It would be used like so:

import { Table } from '~/components';

export const MyTable = ({ items }) => {
  return (
    <Table>
      <Table.Thr>
        <Table.Th>Name</Table.Th>
      </Table.Thr>
      {items.map((item) => (
        <Table.Tr>
          <Table.Td>{item.name}</Table.Td>
        </Table.Tr>
      ))}
    </Table>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.