<!-- Protocore Design System — ProductCard -->
# ProductCard

- **Category:** Cards (`cards`)
- **Slug:** `cards/product-card`
- **Status:** stable
- **Platforms:** web
- **Import:** `import { ProductCard } from "@protocore/pds";`
- **Docs:** https://pds.protocore.io/components/cards/product-card

> An illustrated product card — art panel, eyebrow, title, one-line body, a mono tag row, and an outbound footer link, with a [ 0N ] index.

## When to use it

Use **ProductCard** for a catalogue of products, APIs, or features where each entry wants an enumerator, an illustration, a metadata tag row, and a *link out* to a detail page. It's the fully-loaded member of the tile family. If you don't need the index / tags / link — just art + text — drop to the generic **Tile**. For a numbered *principle* (no media, no link), use **PrincipleTile**. For a non-media grouping, use **Card**. Note the `title` prop is required on ProductCard (a product must be named), unlike Tile where it's optional.

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `art` | `ReactNode` | no | — | The illustration panel — usually a `<LineArt>`. |
| `artHeight` | `number` | no | `200` | Illustration panel height in px. Default `200`. |
| `children` | `ReactNode` | no | — | One-line description body. |
| `className` | `string` | no | — | — |
| `eyebrow` | `ReactNode` | no | — | Mono uppercase eyebrow above the title. |
| `href` | `string` | no | — | Footer link destination — renders the outbound link when set. |
| `index` | `number` | no | — | Enumerator pinned top-right, rendered as `[ 0N ]`. |
| `linkLabel` | `ReactNode` | no | `View` | Footer link label. Default `"View"`. |
| `style` | `CSSProperties` | no | — | — |
| `tags` | `ReactNode[]` | no | — | Mono metadata tags rendered in a row beneath the body. |
| `target` | `string` | no | — | Anchor target for the footer link. |
| `title` | `ReactNode` | yes | — | Product title. |

## Examples

### Basics

A `[ 0N ]` `index` pins top-right, an `art` panel sits above the `eyebrow` + `title` + one-line body, a `tags` array renders a mono metadata row, and `href` turns the footer into an outbound link (`linkLabel` defaults to "View").

```tsx
import { ProductCard, LineArt } from "@protocore/pds";

export default function ProductCardBasics() {
  return (
    <div style={{ maxWidth: 360 }}>
      <ProductCard
        index={1}
        eyebrow="API"
        title="Value Transfer"
        art={<LineArt variant="lens" animate={false} />}
        tags={["REST", "gRPC", "v2"]}
        href="#"
        linkLabel="View reference"
      >
        Move value across networks with guaranteed finality and no wrapped tokens.
      </ProductCard>
    </div>
  );
}
```

### Product grid

The intended layout: a responsive n-up grid of enumerated products, each with its own line-art field.

```tsx
import { ProductCard, LineArt } from "@protocore/pds";

const products = [
  { title: "Value Transfer", variant: "lens", body: "Move value with guaranteed finality." },
  { title: "Swaps", variant: "swaps", body: "Atomic cross-network swaps over unified liquidity." },
  { title: "Messaging", variant: "nexus", body: "Send arbitrary data between connected networks." },
] as const;

export default function ProductCardGrid() {
  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(auto-fit, minmax(260px, 1fr))",
        gap: 24,
      }}
    >
      {products.map((p, i) => (
        <ProductCard
          key={p.title}
          index={i + 1}
          eyebrow="API"
          title={p.title}
          art={<LineArt variant={p.variant} animate={false} />}
          href="#"
        >
          {p.body}
        </ProductCard>
      ))}
    </div>
  );
}
```

## Usage

**Do**

- Give each card a distinct `LineArt` variant so a grid reads as a set of different products.
- Keep the body to a single line — ProductCard is a scannable index entry, not a spec sheet.
- Use the `tags` row for stable metadata (protocol, version, transport), rendered as-typed mono.
- Set `href` (and `target`/`linkLabel`) so every card has one clear way through to detail.

**Don't**

- Don't overflow the `tags` row with more than a few chips; it's metadata, not navigation.
- Don't omit `title` — it's required and names the product.
- Don't use ProductCard for content with no destination; if there's nowhere to go, Tile is the honest choice.
- Don't put multiple links in the body; the footer link is the card's single outbound action.

## Accessibility

**Notes**

- The footer link is a real `<a>` — it's keyboard-focusable and reads its `linkLabel`. The `↗︎` arrow is `aria-hidden`; keep the label meaningful ("View reference"), not just "View", when several cards share a page.
- The `[ 0N ]` index is decorative enumeration; don't encode essential meaning in the number alone.
- Wrap a product grid in a list so screen readers announce how many products there are.

## Related

`tile`, `principle-tile`, `card`, `tag`

---

© Protocore. All rights reserved. Use of the Protocore Design System requires prior written authorization from Protocore (contact@protocore.io). These machine-readable materials must not be ingested into ML-training datasets or derivative design systems. See https://pds.protocore.io/legal/
