Create a reusable table with react, styled-components and compound components design pattern
Joseph Mukorivo
Posted on April 2, 2021
So I have been using react for about 10 months now after switching from a framework I thought I will never leave, you guessed it 🤗 Angular. Angular code was clean and readable and I loved it because it was strongly typed by default (😊 of course that's the beauty of TypeScript).
When my colleague introduced me to React, I said to my self how can this guy introduce me to such a mess, writing jsx was a bit weird to me at first but trust me once you start writing jsx you will never go back.
I started looking for design patterns to make my react code clean and reusable. During this journey, I came across compound components and I started using them with a CSS-in-JS library (styled-components), and I have to say this😎 I was in love😍. My code looked clean and it was also easy to debug.
If you have used a native HTML <select>
and <option>
you can easily understand the concept behind compound components.
<select>
<option value="value1">key1</option>
<option value="value2">key2</option>
<option value="value3">key3</option>
</select>
If you try to use one without the other it would not work, and also it doesn't make sense.
Now, let's get a look at our React <Table />
component that exposes a compound component to understand these principles further. Here is how it looks like.
<Table>
<Table.Head>
<Table.TR>
<Table.TH>Heading 1</Table.TH>
<Table.TH>Heading 2</Table.TH>
</Table.TR>
</Table.Head>
<Table.Body>
<Table.TR>
<Table.TH>data 1</Table.TH>
<Table.TH>data 2</Table.TH>
</Table.TR>
<Table.TR>
<Table.TH>data 3</Table.TH>
<Table.TH>data 4</Table.TH>
</Table.TR>
</Table.Body>
</Table>
But before we get to that, this is how I structure my components. Let me know if you have a better way of structuring components I would love to try it out.
📦components
┣ 📂table
┣ 📂styles
┃ ┗ 📜table.js
┗ 📜index.js
All my styles will be in the styles directory and index.js file imports the styled components from the styles directory. Below is how I will style my table. We are ignoring css however just to keep the post short.
import styled from 'styled-components';
export const StyledTable = styled.table`
// custom css goes here
`;
export const THead = styled.thead`
// custom css goes here
`;
export const TFoot = styled.tfoot`
// custom css goes here
`;
export const TBody = styled.tbody`
// custom css goes here
`;
export const TR = styled.tr`
// custom css goes here
`;
export const TH = styled.th`
// custom css goes here
`;
export const TD = styled.td`
// custom css goes here
`;
Now in the index.js that's where all the action is. Remember with our table component we are exporting just the table component and the other components we accessing them from the table component using the dot notation.
import { StyledTable, THead, TBody, TFoot, TH, TR, TD } from './styles/table';
export const Table = ({ children, ...rest }) => {
return <StyledTable {...rest}>{children}</StyledTable>;
};
Table.Head = ({ children, ...rest }) => {
return <THead {...rest}>{children}</THead>;
};
Table.Body = ({ children, ...rest }) => {
return <TBody {...rest}>{children}</TBody>;
};
Table.Foot = ({ children, ...rest }) => {
return <TFoot {...rest}>{children}</TFoot>;
};
Table.TH = ({ children, ...rest }) => {
return <TH {...rest}>{children}</TH>;
};
Table.TR = ({ children, ...rest }) => {
return <TR {...rest}>{children}</TR>;
};
Table.TD = ({ children, ...rest }) => {
return <TD {...rest}>{children}</TD>;
};
I know I have to explain some things here like how we are accessing these other components when we are not directly exporting them and how the children prop works.
The only component that we are exporting here is the <Table/>
component which wraps the <StyledTable/>
component. We then use the dot notation to attach other components to the <Table/>
component. If we were using class components we will use the static keyword to do the same thing. We can now for example access the styled table row like so <Table.TR/>
Anything passed between the opening and closing tags of a component can be accessed using the children
prop in react, for example, if we write this code <Table.TR>data</Table.TR>
, props.children will be equal to 'data'. That's basically how the children prop works.
We want the end-users of our components to be able to customize them so we are taking everything they are passing as props and spread it on the styled component using the object destructuring syntax {..rest}
.
I hope this post helped you understand compound components. Feel free to comment on areas you need clarity I will respond, or areas you think I need to improve. In the future, we will create a dropdown component using this pattern but now there will be state and we will be using custom hooks and the Context API to manage the state of the dropdown.
Photo by Fabian Irsara on Unsplash
Posted on April 2, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
May 26, 2024