Deck
Browse the catalog

Build / Molecules

CoverCard

  • molecule
  • play-fn

A card-shaped box with a photograph behind it.

Two things every card with a cover needs, in one place. The first is the shape: the same fixed 1.75:1 box lying down and 1:1.75 stood up that every card in Deck holds, turned by useCardOrientation.

The second is what a photograph does to the colours on top of it. The scrim is dark in both light and dark mode — a photograph is not a palette — so everything inside reads against a fixed on-color rather than the page's. That is the --deck-color-cover-* pair, and this component re-points the solid-surface contract at it, which is what makes Text, Heading, Badge and Button come out right in here without any of them knowing they are on a photo.

A card with no cover is the brand under the same scrim — quieter, not broken.

import { CoverCard } from '@meetcard/deck'

Example

<CoverCard coverSrc={cover}> <Heading level={2}>RevOps Summit</Heading> </CoverCard>

Stories

Every preview below is the real component, rendered in this page from the same story Storybook runs. The width control resizes each preview's container; CSS media queries still follow the browser window, so breakpoint behaviour is worth checking in Storybook.

The shape and the photograph. Everything inside reads against the scrim's own on-color rather than the page's — Badge and Text come out right in here without knowing they are on a photo.

Default
Source
const Default = () => <CoverCard
    coverSrc={'data:image/svg+xml;utf8,' +
    encodeURIComponent(
      `<svg xmlns="http://www.w3.org/2000/svg" width="560" height="320">
         <rect width="560" height="320" fill="#fdfbf7"/>
         <circle cx="150" cy="90" r="130" fill="#ffe9c7"/>
         <circle cx="430" cy="240" r="170" fill="#dbeee4"/>
         <rect x="240" y="40" width="120" height="240" fill="#fff6e0"/>
       </svg>`,
    )}>(<>
      <Badge tone="success" size="sm">
        Attending
      </Badge>
      <Heading level={2} size="lg" family="serif" style={{ margin: 0 }}>
        RevOps Summit
      </Heading>
      <Text size="sm">Austin Convention Center</Text>
    </>)</CoverCard>;

Stood up on a phone, like every card.

On A Phone
Source
const OnAPhone = () => <CoverCard
    coverSrc={'data:image/svg+xml;utf8,' +
    encodeURIComponent(
      `<svg xmlns="http://www.w3.org/2000/svg" width="560" height="320">
         <rect width="560" height="320" fill="#fdfbf7"/>
         <circle cx="150" cy="90" r="130" fill="#ffe9c7"/>
         <circle cx="430" cy="240" r="170" fill="#dbeee4"/>
         <rect x="240" y="40" width="120" height="240" fill="#fff6e0"/>
       </svg>`,
    )}>(<>
      <Badge tone="success" size="sm">
        Attending
      </Badge>
      <Heading level={2} size="lg" family="serif" style={{ margin: 0 }}>
        RevOps Summit
      </Heading>
      <Text size="sm">Austin Convention Center</Text>
    </>)</CoverCard>;

Blurred, for a surface whose job is to be read. EventHeaderCard does this: a long name over a sharp picture is a name you have to work at.

Blurred Cover
Source
const BlurredCover = () => <CoverCard
    coverSrc={'data:image/svg+xml;utf8,' +
    encodeURIComponent(
      `<svg xmlns="http://www.w3.org/2000/svg" width="560" height="320">
         <rect width="560" height="320" fill="#fdfbf7"/>
         <circle cx="150" cy="90" r="130" fill="#ffe9c7"/>
         <circle cx="430" cy="240" r="170" fill="#dbeee4"/>
         <rect x="240" y="40" width="120" height="240" fill="#fff6e0"/>
       </svg>`,
    )}
    blurCover>(<>
      <Badge tone="success" size="sm">
        Attending
      </Badge>
      <Heading level={2} size="lg" family="serif" style={{ margin: 0 }}>
        RevOps Summit
      </Heading>
      <Text size="sm">Austin Convention Center</Text>
    </>)</CoverCard>;

No photo. The brand under the same scrim — a quieter card, not a broken one, so a card is never waiting on an image to look finished.

Without A Cover
Source
const WithoutACover = () => <CoverCard coverSrc={undefined}>(<>
      <Badge tone="success" size="sm">
        Attending
      </Badge>
      <Heading level={2} size="lg" family="serif" style={{ margin: 0 }}>
        RevOps Summit
      </Heading>
      <Text size="sm">Austin Convention Center</Text>
    </>)</CoverCard>;

Props

PropTypeDefaultDescription
childrenrequiredReactNode——
as'article' | 'div' | 'section' | 'header''article'Element to render. article by default.
blurCoverbooleanfalseBlur the photo. For a surface whose job is to be read — a header with a long name over it — where a sharp picture competes with the words. Default off: a card is looked at more than it is read.
coverSrcstring—The photo behind the card. Decorative — it says which card this is at a glance, and everything it needs to say in words is said in the content.
orientationResolvedCardOrientation | 'responsive'—Which way up. Default responsive.
scrim'bottom' | 'top' | 'edges''bottom'Where the scrim is heaviest, which is wherever the words are. bottom by default — a header reads from the foot up. edges darkens both ends for a card with something at the top and a strip along the bottom.

Also accepts everything from HTMLAttributes, so id, data-* and event handlers pass straight through.

Open in Storybookfor controls, the a11y panel and the interaction runner.