Card

Cover Card

Card with a full-bleed cover image that zooms while the whole card lifts on hover or focus, plus header, title, description, action and a one-line truncated footer. Built on the stock Card.

The source comes with full access.

One payment of $149 ($49 for now) opens the source right here and lets the CLI install every paid component, with lifetime updates.

Installation

pnpm dlx shadcn add @01orbital/cover-card
npx shadcn add @01orbital/cover-card
yarn shadcn add @01orbital/cover-card
bunx --bun shadcn add @01orbital/cover-card

Part of the 01orbital library. With a license, put ORBITAL_TOKEN in .env.local and the same command installs it (licensed install, pricing).

It lands at components/card/cover-card.tsx, as source you own and edit.

The example also uses button and section. Install them too:

pnpm dlx shadcn add @01orbital/button @01orbital/section
npx shadcn add @01orbital/button @01orbital/section
yarn shadcn add @01orbital/button @01orbital/section
bunx --bun shadcn add @01orbital/button @01orbital/section

The example also imports @phosphor-icons/react from npm, which the install does not add:

pnpm add @phosphor-icons/react
npm install @phosphor-icons/react
yarn add @phosphor-icons/react
bun add @phosphor-icons/react

Usage

import { ArrowRightIcon } from "@phosphor-icons/react/dist/ssr"
import { cn } from "cn"

import {
  CoverCard,
  CoverCardAction,
  CoverCardCover,
  CoverCardDescription,
  CoverCardFooter,
  CoverCardHeader,
  CoverCardTitle,
} from "@/components/card/cover-card"
import {
  Section,
  SectionContent,
} from "@/components/editorial/section"
import { buttonVariants } from "@/components/ui/button"

const COPY = {
  items: [
    {
      title: "Halcyon",
      description: "Technology",
      image:
        "https://01orbital.dev/art/kit/celestograph-369187-meridian-1b.png",
      footer: "A support workspace built around palette-driven agents",
    },
    {
      title: "Lantern",
      description: "Healthcare",
      image: "https://01orbital.dev/art/kit/celestograph-61495-gesso-2b.png",
      footer: "Lantern's intake agent greets patients in calm teal",
    },
  ],
} as const

export default function CoverCardDemo() {
  return (
    <Section>
      <SectionContent className="items-center">
        <div className="grid w-full max-w-4xl gap-5 sm:grid-cols-2">
          {COPY.items.map((item) => (
            <CoverCard key={item.title} className="aspect-square">
              <CoverCardHeader>
                <CoverCardTitle>{item.title}</CoverCardTitle>
                <CoverCardDescription>{item.description}</CoverCardDescription>
                <CoverCardAction>
                  <a
                    href="#"
                    data-slot="button"
                    className={cn(
                      buttonVariants({ variant: "secondary", size: "icon-lg" })
                    )}
                    aria-label={`Read about ${item.title}`}
                  >
                    <ArrowRightIcon aria-hidden="true" />
                  </a>
                </CoverCardAction>
              </CoverCardHeader>
              <CoverCardCover>
                <img src={item.image} alt="" loading="lazy" />
              </CoverCardCover>
              <CoverCardFooter>{item.footer}</CoverCardFooter>
            </CoverCard>
          ))}
        </div>
      </SectionContent>
    </Section>
  )
}

Anatomy

Cover Card is built from 7 parts. In the example they nest like this:

CoverCard
├─ CoverCardHeader
│  ├─ CoverCardTitle
│  ├─ CoverCardDescription
│  └─ CoverCardAction
├─ CoverCardCover
└─ CoverCardFooter
  • CoverCard: A Card with a picture cover. On hover, or while something inside it has focus, the card lifts and its shadow deepens, and the cover image zooms in slightly. For readers who prefer reduced motion, the lift and zoom are skipped and only the shadow changes.
  • CoverCardHeader: The top of a CoverCard, built on the stock CardHeader. It holds the CoverCardTitle, CoverCardDescription and an optional CoverCardAction.
  • CoverCardTitle: The card's title, an h3 on one line; a long title ends in an ellipsis. Pass render to use another heading level.
  • CoverCardDescription: One line of muted text under the title; a long line ends in an ellipsis.
  • CoverCardAction: A place at the far edge of the CoverCardHeader for a button or link. It is the stock CardAction.
  • CoverCardCover: The picture area of a CoverCard. It runs from edge to edge across the card and takes whatever height the card has left, at least 10rem.
  • CoverCardFooter: One line of text under the cover, padded to match the card. A long line ends in an ellipsis instead of wrapping, so it never takes height from the cover.

API reference

CoverCard

A Card with a picture cover. On hover, or while something inside it has focus, the card lifts and its shadow deepens, and the cover image zooms in slightly. For readers who prefer reduced motion, the lift and zoom are skipped and only the shadow changes.

Give the card a height, for example aspect-square, so the CoverCardCover has room to fill. Put a CoverCardHeader, CoverCardCover and CoverCardFooter inside.

Prop

Type

It also accepts the HTML attributes of the element it renders.

CoverCardHeader

The top of a CoverCard, built on the stock CardHeader. It holds the CoverCardTitle, CoverCardDescription and an optional CoverCardAction.

It accepts the HTML attributes of the element it renders.

CoverCardTitle

The card's title, an h3 on one line; a long title ends in an ellipsis. Pass render to use another heading level.

It accepts the props of the Base UI part it wraps, and the HTML attributes of the element it renders.

CoverCardDescription

One line of muted text under the title; a long line ends in an ellipsis.

It accepts the HTML attributes of the element it renders.

CoverCardAction

A place at the far edge of the CoverCardHeader for a button or link. It is the stock CardAction.

It accepts the HTML attributes of the element it renders.

CoverCardCover

The picture area of a CoverCard. It runs from edge to edge across the card and takes whatever height the card has left, at least 10rem.

Put one img directly inside. It fills the cover, is cropped to fit, and zooms with the card on hover or focus.

It accepts the HTML attributes of the element it renders.

One line of text under the cover, padded to match the card. A long line ends in an ellipsis instead of wrapping, so it never takes height from the cover.

It accepts the HTML attributes of the element it renders.

Dependencies

npm: @base-ui/react, cn. The CLI installs them for you.

Registry pieces it installs with it:

  • card