Skip to content
lib components / Structure

Card

Use this component to group information, controls and actions about a single topic.

import { Card } from "@siteimprove/fancylib";

Our structure components are strongly interconnected. Make sure to read the structure component guide, to find out which components you need and how to combine them correctly.

#Examples

The card component is the most fundamental building block of our UI. It is used on just about every single page in the platform. It's a flexible and visible container, which purpose is to group information, controls and actions about a single topic. This provides users with a clear and scannable overview of a page's main sections. The following examples showcase the card's default implementation and most important variants.

#Default

Here is an example of the card component in it's most basic form. An empty card wouldn't have made sense, since a card's purpose is to group content. In fact, without the paragraph, the card in the example would have been invisible.

Without this paragraph, this card would disappear.

<Card aria-label="A card without a header must have an aria-label"> <Paragraph>Without this paragraph, this card would disappear.</Paragraph> </Card>

Cards should almost always have a header. The rare exception is when a card serves as a container for structural or navigational content, that should not be exportable to a dashboard or does not contain data. The page-level variant of our Tabs component is an example of this exception.

To add a header to a card, simply add a Card.Header component as the first child, as shown in the example below. If you look at the example's HTML output, you'll see that the text inside the Card.Header is automatically turned into an H2 heading. You can put a different heading, such as an H3 inside the Card.Header. However, this generally only makes sense when a card is placed inside another card, which is a rare occurrence.

The example's HTML output also shows that the card's aria-labelledby property automatically points to the card header. If you don't add a header to a card, you need to provide the card with an aria-label yourself, using either its aria-label or aria-labelledby property.

Card header

Check out this example's HTML output. The text above explains why.

<Card> <Card.Header>Card header</Card.Header> <Content> <TextContainer article> <Paragraph>Check out this example's HTML output. The text above explains why.</Paragraph> </TextContainer> </Content> </Card>

Cards can optionally contain a footer. This section is intended for information and actions that relate to the Card as a whole. In most cases, that will be the Action Bar component, which provides users with a set of actions related to the completion of a task.

Add a footer by placing a Card.Footer component inside a Card component as its last child.

Card header

Card content

<Card> <Card.Header>Card header</Card.Header> <Content> <TextContainer article> <Paragraph>Card content</Paragraph> </TextContainer> </Content> <Card.Footer> <Content>Card footer</Content> </Card.Footer> </Card>

#Padding

A card does not have any padding by default. Whether you need to add padding depends on what you're putting in the card. For instance, (dead link) tables should take up the full width of a card, but a (dead link) chart, (dead link)form, or text-container, should always have padding. You add this padding by using the content and layout components (see example below).

Lorem Ipsum

What is Lorem Ipsum?

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.

Why do we use it?

It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).

<Card> <Card.Header>Lorem Ipsum</Card.Header> <Content.Layout padding="large"> <Content flex="1 1 auto"> <TextContainer> <H3>What is Lorem Ipsum?</H3> <Paragraph> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. </Paragraph> </TextContainer> </Content> <Content flex="1 1 auto"> <TextContainer> <H3>Why do we use it?</H3> <Paragraph> It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like). </Paragraph> </TextContainer> </Content> </Content.Layout> </Card>

#Size

A card's height is determined by the height of its content, which can change due to user action or input. It's not something you actively set.

In contrast, a card's width is something you actively set, when you want to deviate from its default width of 100%. However, you don't use one of the card's properties for this. Instead, you wrap each card in a grid.section and use this component's size property to set the card's size.

These Grid.Section components then need to be wrapped in a grid component, which lays out the cards in a grid. You can see an example of all this below. The guide features more information about how these structure components can be combined.

Full (default)

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at odio elit. Donec laoreet massa justo, at sagittis nulla volutpat vitae. Nullam efficitur efficitur justo non egestas.

Half

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at odio elit. Donec laoreet massa justo, at sagittis nulla volutpat vitae. Nullam efficitur efficitur justo non egestas.

Fourth A

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at odio elit. Donec laoreet massa justo, at sagittis nulla volutpat vitae. Nullam efficitur efficitur justo non egestas.

Fourth B

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at odio elit. Donec laoreet massa justo, at sagittis nulla volutpat vitae. Nullam efficitur efficitur justo non egestas.

Third

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at odio elit. Donec laoreet massa justo, at sagittis nulla volutpat vitae. Nullam efficitur efficitur justo non egestas.

Two thirds

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at odio elit. Donec laoreet massa justo, at sagittis nulla volutpat vitae. Nullam efficitur efficitur justo non egestas.

<Grid> <Grid.Section> <Card> <Card.Header>Full (default)</Card.Header> <Content> <TextContainer article> <Paragraph> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at odio elit. Donec laoreet massa justo, at sagittis nulla volutpat vitae. Nullam efficitur efficitur justo non egestas. </Paragraph> </TextContainer> </Content> </Card> </Grid.Section> <Grid.Section size="half"> <Card> <Card.Header>Half</Card.Header> <Content> <TextContainer article> <Paragraph> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at odio elit. Donec laoreet massa justo, at sagittis nulla volutpat vitae. Nullam efficitur efficitur justo non egestas. </Paragraph> </TextContainer> </Content> </Card> </Grid.Section> <Grid.Section size="fourth"> <Card> <Card.Header>Fourth A</Card.Header> <Content> <TextContainer article> <Paragraph> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at odio elit. Donec laoreet massa justo, at sagittis nulla volutpat vitae. Nullam efficitur efficitur justo non egestas. </Paragraph> </TextContainer> </Content> </Card> </Grid.Section> <Grid.Section size="fourth"> <Card> <Card.Header>Fourth B</Card.Header> <Content> <TextContainer article> <Paragraph> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at odio elit. Donec laoreet massa justo, at sagittis nulla volutpat vitae. Nullam efficitur efficitur justo non egestas. </Paragraph> </TextContainer> </Content> </Card> </Grid.Section> <Grid.Section size="third"> <Card> <Card.Header>Third</Card.Header> <Content> <TextContainer article> <Paragraph> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at odio elit. Donec laoreet massa justo, at sagittis nulla volutpat vitae. Nullam efficitur efficitur justo non egestas. </Paragraph> </TextContainer> </Content> </Card> </Grid.Section> <Grid.Section size="twothirds"> <Card> <Card.Header>Two thirds</Card.Header> <Content> <TextContainer article> <Paragraph> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at odio elit. Donec laoreet massa justo, at sagittis nulla volutpat vitae. Nullam efficitur efficitur justo non egestas. </Paragraph> </TextContainer> </Content> </Card> </Grid.Section> </Grid>

#Properties

Example 1: A card without a header, containing a paragraph wrapped in a content component for padding.

PropertyDescriptionDefinedValue
childrenOptional
elementThe content of the card
cardRefOptional
objectSet the React ref
idOptional
stringSet the id attribute
contextIdOptional
stringProvide a id to be used in `CardIdContext`, otherwise a unique one is generated. `CardIdContext` is used by `CardHeader`
aria-labelOptional
stringLabels the card, Cards must be labeled either via `aria-label`, `aria-labelledby` or having a `<CardHeader>` as children
aria-labelledbyOptional
stringLabels the card via an id, Cards must be labeled either via `aria-label`, `aria-labelledby` or having a `<CardHeader>` as children
unlabelledOptional
booleanUse this if you have a card with no Card.Header that doesn't make sense to be labelled
data-componentOptional
stringName of the component. Should only be set by components since it needs to stable. Used to track component usage
classNameOptional
stringCustom className that's applied to the outermost element (only intended for special cases)
styleOptional
objectStyle object to apply custom inline styles (only intended for special cases)
data-observe-keyOptional
stringUnique string, used by external script e.g. for event tracking

#Guidelines

#Best practices

  • Always add a header to a card, using the Card.Header component. Except when the card serves as a container for structural or navigational content, that should not be exportable to a dashboard or does not contain data.
  • Provide cards without a header with an aria-label, using either thearia-label or aria-labelledby property.
  • To add padding to a card, use a content component. It can also be used to control the position and alignment of the card’s contents.
  • When you have multiple content components inside a card, use a Content.Layout component to control their padding, alignment, and positioning.
  • Don’t set an explicit size for a card’s height, let it be implicitely determined by the height of its contents.
  • Use a full width card when it’s the only card on the page.
  • Choose a width for a card based on its contents and context (the other cards on the page).
  • To adjust the width of a card, wrap it in a grid.section and use this component’s size property.
  • When you have multiple cards on a page, wrap them in a grid component.

#Do not use when

You need to create sections inside of a card or overlay, such as a modal or sidepanel. Instead, create these sections by using the Content.Layout, content, heading, and divider components. Also, when a card's contents requires sections, consider whether these shouldn't be separate cards instead.

#Accessibility

The card header should contain a heading with an appropriate level. In most cases, this will be an <Header.h2> level heading. Deviating from this level can be appropriate when, for instance, a card is nested inside an other card. However, make sure never to skip heading levels. For more information, see the heading component's documentation page.

Explore detailed guidelines for this component: Accessibility Specifications

#Writing

  • A card should always have a heading. Except when it serves as a container for structural or navigational content that isn’t dashboardable.
  • A card's heading should briefly describe the contents of the card, or what the user can do within it.
  • Try to avoid repeating the page heading in the card heading.
  • If a card is the first step in a workflow, the heading may serve as a prompt or a call-to-action.
  • A dashboardable card's heading should still make sense when the card is exported to a dashboard.
  • Make sure to read the writing guidelines of the Heading component.