Card

A content card, outline or filled, plain, numbered, illustrated, linked or large, for product surfaces and base.org sections.

Card is a content tile: a numbered step, an illustrated reason, a large lead claim or a linked article. Product surfaces and base.org sections use the same component at different sizes and variants. It is a compound component: the card provides the surface, and the slots Card.Number, Card.Icon, Card.Title, Card.Description, Card.Meta, Card.Media and Card.Footer place the content. With an href the whole card is one link. A card stretches to fill its cell in a Card Group, with the text pinned to the bottom. The slots are also named exports (CardTitle, CardNumber, and so on); use those in a React Server Component, where the Card.Title properties of the client module are not available.

import { Card } from '@base-org/bds-web/product/card';

<Card>
  <Card.Number>01</Card.Number>
  <Card.Title>Deposit</Card.Title>
  <Card.Description>A customer deposits supported stablecoins in your app.</Card.Description>
</Card>;

Variants

Each card is shown on its own here; Card Group lays several out as a section grid.

Outline

The default (variant="outline"): a 12px-radius surface with a hairline border, 16px of padding (24px from md), a title and body copy. The title uses the Product title-2 step and the copy body. These sizes and the padding are today's values; the base.org sizes follow once design settles them.

Deposit

A customer deposits supported stablecoins in your app.

<Card>
<Card.Title>Deposit</Card.Title>
<Card.Description>A customer deposits supported stablecoins in your app.</Card.Description>
</Card>

Numbered

Add a Card.Number and it sits top-left in brand blue, 24px above the text. The text is pinned to the bottom, so a card that is taller than its content leaves the gap between the number and the text.

01

Deposit

A customer deposits supported stablecoins in your app.

<Card>
<Card.Number>01</Card.Number>
<Card.Title>Deposit</Card.Title>
<Card.Description>A customer deposits supported stablecoins in your app.</Card.Description>
</Card>

With illustration

Put a feature icon in Card.Icon and it takes the number's place: top-left at 64px, 24px above the text. Move it with position, below. The card passes its hover and in-view state to the illustration, so it plays without an isHovered prop.

Grow and retain assets on your platform

Give customers additional utility for supported balances, and a way to access liquidity without selling.

<Card>
<Card.Icon><GenerateRevenueIcon /></Card.Icon>
<Card.Title>Grow and retain assets on your platform</Card.Title>
<Card.Description>Give customers additional utility for supported balances, and a way to access liquidity without selling.</Card.Description>
</Card>

Illustration position

Card.Icon takes a position: top-left (the default), top-right, or bottom-right (the default on a large card). With bottom-right the text moves to the top and the illustration takes the spare height below it, with at least 40px between them. The position applies wherever Card.Icon sits in the markup.

Grow assets

More to do with balances.

Scale up

Earn from stablecoin balances.

Stand out

Offer yield and borrowing.

<Card>
<Card.Icon position="top-left"><GenerateRevenueIcon /></Card.Icon>
<Card.Title>Grow assets</Card.Title>
<Card.Description>More to do with balances.</Card.Description>
</Card>

<Card>
<Card.Icon position="top-right"><LiquidityIcon /></Card.Icon>
<Card.Title>Scale up</Card.Title>
<Card.Description>Earn from stablecoin balances.</Card.Description>
</Card>

<Card>
<Card.Icon position="bottom-right"><EcosystemIcon /></Card.Icon>
<Card.Title>Stand out</Card.Title>
<Card.Description>Offer yield and borrowing.</Card.Description>
</Card>
PositionUse for
top-leftThe default, in the number's place.
top-rightA card whose illustration should read after the title.
bottom-rightThe default on a large card; any card with the text first.

Large

size="lg" is the large card that leads a Why Base section: a display-size title, body copy, and the illustration bottom-right by default. It is at least 520px tall from md.

Built on the trust of Coinbase

Base is built by Coinbase, with the security and compliance practices of a public company.

<Card size="lg">
<Card.Title highlight="Coinbase">Built on the trust of Coinbase</Card.Title>
<Card.Description>Base is built by Coinbase, with the security and compliance practices of a public company.</Card.Description>
<Card.Icon><CoinbaseTrustIcon /></Card.Icon>
</Card>
SizeUse for
defaultA card in a section grid: plain, numbered or illustrated.
lgThe first, larger card of a Why Base section: a display-size title, at least 520px tall from md, and more padding.

Filled

variant="filled" is a borderless gray tile for dense grids and carousels, where a border on every card would add noise. The surface is bds-gray-5 (a faint white wash in dark mode) and clips its content to the 12px corners. The padding is 20px at the sides, 16px at the top and 20px at the bottom. The variant changes only the surface and padding: the slots keep the type steps of the card's size, so a filled card reads the same as an outline one. A large filled card keeps the large layout on the gray surface.

Base Builder Grants

Retroactive grants for builders shipping onchain apps on Base.

May 1, 2025

<Card variant="filled">
<Card.Title>Base Builder Grants</Card.Title>
<Card.Description>Retroactive grants for builders shipping onchain apps on Base.</Card.Description>
<Card.Meta>May 1, 2025</Card.Meta>
</Card>
VariantUse for
outlineThe default: section grids where each card needs its own edge.
filledCards in a carousel or a dense grid, where borders on every card would add noise. The blog post card below is one example.

Linked card

Give the card an href and it renders a single link, an a, in place of the div. target and rel pass through. The surface darkens while hovered (bds-gray-5 on an outline card, bds-gray-10 on a filled one) and shows the focus ring on keyboard focus. The link's accessible name is all of its text, so keep the content short.

<Card href="/docs/product/card">
<Card.Title>Deposit</Card.Title>
<Card.Description>A customer deposits supported stablecoins in your app.</Card.Description>
</Card>

Blog post

One use of a filled, linked card is the base.org blog post card, as in the home page's Latest on Base carousel and the /blog grid: a bleeding 2:1 cover, a title, a description and a date in Card.Meta. The base.org type steps and the clamping come from className on the slots, not from the variant. The ! makes the brand step win over the slot's own Product step. Mark a draft with a Badge placed over the cover; Card.Media with bleed is positioned, so the badge can sit at its corner.

<Card variant="filled" href="/blog/post">
<Card.Media bleed className="aspect-2/1 bg-bds-blue-60">
  <img src="/images/cover.webp" alt="" className="size-full object-cover" />
  <Badge variant="label" className="absolute top-3 left-3">Draft</Badge>
</Card.Media>
<Card.Title className="truncate text-brand-headline!">Base Builder Grants</Card.Title>
<Card.Description className="line-clamp-3 text-brand-body!">
  Retroactive grants for builders shipping onchain apps on Base.
</Card.Description>
<Card.Meta className="text-brand-label!">
  <time dateTime="2025-05-01">May 1, 2025</time>
</Card.Meta>
</Card>

The number and the illustration are slots, not sizes: a card is numbered or illustrated by what you put in it, and the two sit in the same place.

Slots

Highlight

Card.Title takes a highlight: the first match of that substring in a string title is coloured brand blue.

Built for everyone

Anyone can build on Base, and anyone can use what gets built.

<CardTitle highlight="for everyone">Built for everyone</CardTitle>

Meta

Card.Meta is a small, light gray line (bds-gray-40) under the description, such as a date or a read time. Wrap a date in a time element.

Deposit

A customer deposits supported stablecoins in your app.

2 min read

<Card>
<Card.Title>Deposit</Card.Title>
<Card.Description>A customer deposits supported stablecoins in your app.</Card.Description>
<Card.Meta>2 min read</Card.Meta>
</Card>

Bleed

Card.Media with bleed runs edge to edge across the top of the card: it cancels the card's padding at the sides and the top, takes the card's top corners, and moves to the top wherever it sits in the markup. Set the aspect ratio on the media, such as aspect-2/1 for a blog cover.

Tokenized stocks

Trade US equities onchain, 24 hours a day.

<Card>
<Card.Media bleed className="aspect-2/1 bg-bds-blue-60">
  <img src="/images/..." alt="" />
</Card.Media>
<Card.Title>Tokenized stocks</Card.Title>
<Card.Description>Trade US equities onchain, 24 hours a day.</Card.Description>
</Card>

Card.Media is a clipped, rounded area for an image or an asset illustration. Card.Footer is a row for actions under the text, such as a Button.

Tokenized stocks

Trade US equities onchain, 24 hours a day.

<Card>
<Card.Media>
  <img src="/images/..." alt="" />
</Card.Media>
<Card.Title>Tokenized stocks</Card.Title>
<Card.Description>Trade US equities onchain, 24 hours a day.</Card.Description>
<Card.Footer>
  <Button size="sm" variant="secondary" arrow>Learn More</Button>
</Card.Footer>
</Card>

When to use

Use Card for content tiles: numbered steps or use cases, illustrated reasons, a large lead claim, or a linked article.

Use something else when:

  • The card shows one headline number. Put a Stat in the Card instead of the slots.
  • The card shows a metric with a chart. Use Metric Card.
  • The card holds more than one action. Leave the card without an href and put each action in Card.Footer as a Button; a linked card cannot contain other links or buttons.
  • The action is a short label rather than a tile of content. Use a Button or Link.

Usage

Do

Keep one idea per card: a short title and one or two sentences. Let the illustration or number carry the rest.

Don't

Mix numbered and illustrated tiles in the same grid, or put both a Card.Number and a Card.Icon in one card.

Do

Make the whole card one link with href when the card leads to one page, such as a blog post.

Don't

Put a Button or a Link inside a linked card, or mix outline and filled cards in the same grid.

  • Put Card.Number first and the text after it; the text is pinned to the bottom. Place the illustration with position, not the markup order.
  • Let Card Group set the card size. Use md:row-span-2 and md:col-span-2 on the card for the tall or wide cell, not a height on the card.
  • In dark mode the card surface is dark gray (bds-gray-2), so it lifts off the page; it needs no extra classes.
  • Put a bleeding Card.Media first; it moves to the top anyway, and the reading order then matches what is on screen.

Props

Card

PropTypeDefault
href

Makes the whole card one link: it renders an `a` with a hover state and a focus ring.

TypestringDefault—
isDisabled

Whether the link is disabled.

TypebooleanDefault—
size

`default` is a card whose text sits at the bottom, with an optional

Type"default" | "lg"Defaultdefault
target

The target window for the link. See

TypeHTMLAttributeAnchorTargetDefault—
variant

`outline` is a bordered surface. `filled` is a borderless gray tile for

Type"outline" | "filled"Defaultoutline

Card.Icon

PropTypeDefault
position

Where the illustration sits. Defaults to `top-left` on a `default` card

Type"top-left" | "top-right" | "bottom-right"Default—

Card.Title

PropTypeDefault
highlight

A substring of the title to colour brand blue. Only applies to a string title.

TypestringDefault—

Card.Media

PropTypeDefault
bleed

Runs the media edge to edge across the top of the card, cancelling the

TypebooleanDefaultfalse

Card.Number, Card.Description and Card.Meta take the props of a p, and Card.Footer the props of a div; none adds props of its own. Each slot reads the card's size; Card.Media with bleed also reads the variant to cancel the matching padding.

Accessibility

Card.Title renders an h3, so a section's cards sit under its h2 heading.

The illustration in Card.Icon is decorative and hidden from assistive technology, so the title and description must carry the meaning on their own.

Without an href the card is not interactive and has no hover state beyond playing the illustration. Interactive content inside it, such as a Button in Card.Footer, keeps its own focus ring and keyboard behaviour.

With an href the card is a React Aria Link: one a in the tab order that opens with Enter, with its text as the accessible name and a focus ring on keyboard focus. Do not nest other interactive elements in it. Give the cover image an empty alt when the title already says what the post is, and put a draft Badge inside the link so it is read with the title.