Design Tokens for Mesh have just been released!
Skip to content

A Card component is ideal for encapsulating a discrete piece of content which has a single action. Card provides several elements that allow for multiple variations to suit a variety of contexts.

Installation

bash
npm install @nib/card

Note: You will also need to install the peerDependencies @nib/icons and @nib-components/theme.

Usage

jsx
import Card from '@nib/card';

Note: If you are using this component within a React Server Component (like the NextJS 13 App Router), it is suggested to import Card, CardContent and CardFooter individually.

jsx
import Card, {CardContent, CardFooter} from '@nib/card';
jsx
<Card image="https://via.placeholder.com/900x600" imageAlt="Placeholder">
<CardContent title="Card Heading">
<Copy>Enabling teams to create high-quality products and experiences faster for our members.</Copy>
</CardContent>
<CardFooter>
<Inline space={4} collapseBelow="sm">
<PrimaryButton fullWidth>Get a quote</PrimaryButton>
<SecondaryButton fullWidth>Get a quote</SecondaryButton>
</Inline>
</CardFooter>
</Card>;

Interactive demo

jsx

Note: GreyBox is not a card component, it is purely for demonstration purposes.

Props

Card

PropTypeDefaultDescription
children (required)nodeThe content of the card. Content must be placed within the <Card.Content /> and <Card.Footer /> components.
componentstring or componentdivThe underlying component wrapping the card.
imagestring or elementImage to be added to the Card header. The image used should have an aspect ratio of 3:2. The value can be an <img> or <picture> element.
imageAltstringThe alt tag value for the corresponding image prop. Only works when the image prop provided is a string.
imageLazyLoadingbooleantrueWhether the card image should be loaded lazily.
iconcomponentIcon to be added to the Card header. Must be an icon from the @nib/icons package.
tagcomponentTag to be added to the card. Must be a @nib/tag component.
alignstringleftThe horizontal alignment of the card content. Must be one of left, right or center.
paddingnumber or object4A size from our spacing scale. Can be made responsive by passing an object of breakpoints. Value(s) must be one of 1...10.
horizontalLayoutbooleanfalseWhether to use a the horizontal layout of the Card.
collapseBelowstringA breakpoint value which defines when the horizontalLayout structure should collapse to a vertical card.
reversebooleanWhether to reverse the order of the card columns. Only works with the horizontalLayout prop.
heightstringA fixed height applied to the Card wrapper. Useful when using the horizontalLayout prop.
backgroundstringwhiteA colour background applied around the icon or image of the card. Must be one of light, white, sageGreen, sunsetPink or warmWhite.

Card.Content

PropTypeDefaultDescription
title (required)stringThe card title.
children (required)nodeThe card content.
titleSizenumberThe size of the card title. Must be one of 1, 2, 3, 4, 5, 6.
titleComponentstringThe underlying component of the card title. Must be one of h1, h2, h3, h4, h5, h6, div, label, span, header

Card.Footer

PropTypeDefaultDescription
children (required)nodeThe card footer content.

Card variations

There is an additional card variation exported by this package called FlashCard.

FlashCard

Usage

jsx
import {FlashCard} from '@nib/card';
<FlashCard icon={DoctorGraphicIcon}>
<FlashCard.Content title="5 easy vegan meals">
<Copy>Enabling teams to create high-quality products and experiences faster for our customers.</Copy>
<Inline space={4}>
<Link to="#">Read more</Link>
</Inline>
</FlashCard.Content>
</FlashCard>

Note: If you are using this component within a React Server Component (like the NextJS 13 App Router), it is suggested to import FlashCard, FlashCardContent and FlashCardFooter individually.

jsx
import {FlashCard,FlashCardContent, FlashCardFooter} from '@nib/card';
jsx
<FlashCard icon={DoctorGraphicIcon}>
<FlashCardContent title="5 easy vegan meals">
<Copy>Enabling teams to create high-quality products and experiences faster for our members.</Copy>
<Link to="#">Read more</Link>
</FlashCardContent>
</FlashCard>;

Props

This component has the same props as are outlined above, with the following exceptions used to simplify the component for users:

  • Instead of Card.Content and Card.Footer, the subcomponents are FlashCard.Content and FlashCard.Footer.
  • The horizontalLayout does not apply to this component.
  • Icons are required and therefore the image, imageAlt, and imageLazyLoading props are unavailable.
  • The tag prop is unavailable for this component.

Examples

A Card can be configured to suit a range of contexts and requirements:

Card Heading

Enabling teams to create high-quality products and experiences faster for our customers.

A simple Card without an image or icon.

Tag
Placeholder

Card Heading

Enabling teams to create high-quality products and experiences faster for our customers.


A Card with an image and all available elements displayed and left aligned.

Tag

Card Heading

Enabling teams to create high-quality products and experiences faster for our customers.


A Card with an icon and all available elments displayed and center aligned.

A Card with an image, wrapped in a link.

Card Heading

Enabling teams to create high-quality products and experiences faster for our customers.

Placeholder

A horizontal Card with a fixed height.

5 easy vegan meals

Enabling teams to create high-quality products and experiences faster for our customers.

A basic Flash Card.

Considerations

When using the component prop to wrap the card in a link (i.e. an a tag, or a Gatsby Link), it is important not to use any other clickable content within the card itself. This includes Buttons and Links. The reason for this is that nested links will create screen reader inaccessibility.

The <Card.Footer /> should use action elements such as buttons and links. When using buttons, we advise wrapping multiple buttons in an Inline component with a collapseBelow value set. Using this alongside the fullWidth prop on the Button will ensure the buttons are full width at smaller screen sizes.

If using the Horizontal Card be aware of the limited space for content. The card is split into two equal columns and so there is very little room for things like buttons in the <Card.Footer />, especially on mobile devices. It is recommended to reduce content inside Buttons (to a single word) or to not use Buttons at all. Large content inside <Card.Footer /> can cause card width to grow and floating tag to be cut off.

We are aware of an a11y issue when a card is wrapped in a link where users cannot highlight card content. We will be addressing this in a future release.

Images

The image prop accepts either a string, representing the image source, or an image component. When simply providing a url, ensure the image is an appropriate size, and maintains the correct aspect ratio for optimal display. Note that when a horizontal Card uses the collapseBelow prop, the image may not behave as expected in responsive layouts. In such cases, or if the image rendering does not meet your requirements, you can pass your own image component to the image prop for more customisation including multiple image sizes, types and densities.

Many cards

When using the card component, it is likely that you will want to output a group of cards, and not just one. We recommend using our layout components to place cards alongside one another. There are basically two patterns for doing this.

A single row

For a single row of cards (that collapses to a single column on mobile) we suggest using the Columns and Column layout components:

jsx
<Columns space={{xs: 4, md: 6}} collapseBelow="lg">
<Column flex>
<Card/>
</Column>
<Column flex>
<Card/>
</Column>
<Column flex>
<Card/>
</Column>
</Columns>

This should be used when the number of cards is known, and fits nicely in one row (typically no more than 4).

Multiple rows

For a list of cards that wraps to multiple rows we suggest using the Tiles layout component:

jsx
<Tiles space={4} columns={{ md: 2, xl: 3 }}>
<Card/>
<Card/>
<Card/>
<Card/>
<Card/>
<Card/>
</Tiles>
// or more realistically
<Tiles space={4} columns={{ md: 2, xl: 3 }}>
{cards.map(card => <Card {...card}/>)}
</Tiles>

In this example cards are stacked in a single column on mobile, in two columns from the md breakpoint up until xl, at which point three columns are used. With tiles it doesn't matter how many cards there are, they simply wrap to a new row and carry on.

This should be used when the number of cards is known to be greater than can fit nicely in one row.

Equal card heights

Both approaches should retain equal heights for the cards in the list, and the Card.Content sub-component should be the one to grow to fill the vertical space. Note the flex prop on the Column component in the first example.