React Associated Components
Saturday, July 10, 2021
•272 words
•2 minute read
When building React components I often find myself in situations where there are groups of components that regularly appear together. For example, consider this Card
component that can be used with header, body, and footer components:
import React from 'react';
import { Card } from './Card';
import { CardBody } from './CardBody';
import { CardFooter } from './CardFooter';
import { CardHeader } from './CardHeader';
const App = () => (
<Card>
<CardHeader>A Movie Listing (2021)</CardHeader>
<CardBody>This movie is awesome!</CardBody>
<CardFooter>
<Button>Watch Movie</Button>
</CardFooter>
</Card>
);
It can be rather cumbersome to have to import all of the various components every time we want to use them, especially since every time we use a Card
we'll want to use one or more of these components with it. Likewise, these components won't be used outside the context of a Card
.
Instead, we can make CardHeader
, CardBody
, and CardFooter
associated components1 on the Card
:
import React from 'react';
import { Card } from './Card';
const App = () => (
<Card>
<Card.Header>A Movie Listing (2021)</Card.Header>
<Card.Body>This movie is awesome!</Card.Body>
<Card.Footer>
<Button>Watch Movie</Button>
</Card.Footer>
</Card>
);
Here's what things look like under the hood:
import React from 'react';
import { CardBody } from './CardBody';
import { CardFooter } from './CardFooter';
import { CardHeader } from './CardHeader';
export interface CardProps
extends React.DetailedHTMLProps<
React.HTMLAttributes<HTMLDivElement>,
HTMLDivElement
> {}
export interface Card {
Header: typeof CardHeader;
Body: typeof CardBody;
Footer: typeof CardFooter;
}
export const Card: React.FC<Readonly<CardProps>> & Card = ({
children,
...props
}) => (
// The most basic of `Card`s.
<div {...props}>{children}</div>
);
Card.Header = CardHeader;
Card.Body = CardBody;
Card.Footer = CardFooter;
And that's all there is to it!
1
This name is inspired by Rust's associated types.