Pre-alphaThe registry and the CLI are not published yet.Roadmap
Compositions

Product Card

Product image, name, price, an optional badge and an add-to-cart button, built from Card.

New in

New

Chambray shirtIndigo, 3 colors

$48.00

Add to cart

City daypackNavy, 18 L

$72.00

Add to cart

-20%

Steel bottleSage, 500 ml

$25.60

Add to cart

Smart watchWhite, 41 mm

$199.00

Add to cart

Featured

-20%

$25.60Steel bottleSage, 500 ml
$72.00City daypackNavy, 18 L

New

$29.00Everyday teeBlack, S to XL
$48.00Chambray shirtIndigo, 3 colors

The two variants are separate components with their own code: install the one you need. Default is an outlined card with the image edge to edge and the price under the name. Spotlight is a filled card where a cut-out product floats on the card’s background, price first.

Installation

npx axiom add product-card
pnpm dlx axiom add product-card
yarn dlx axiom add product-card
bun x axiom add product-card

Also copies: card, text, badge, button and their dependencies. The file lands in components/compositions/product-card.tsx.

Product Card brings no tokens of its own: it uses the outlined variant of Card, the highlight variant of Badge and the default Button.

npx axiom add product-card-spotlight
pnpm dlx axiom add product-card-spotlight
yarn dlx axiom add product-card-spotlight
bun x axiom add product-card-spotlight

Also copies: card, text, title, badge, button and their dependencies. The file lands in components/compositions/product-card-spotlight.tsx.

It brings no tokens of its own: it uses the filled variant of Card, the headingSm variant of Title for the price, the highlight variant of Badge and the default Button.

Usage

import { Image } from "react-native";
import { ProductCard } from "@/components/compositions/product-card";

<ProductCard
	title="Chambray shirt"
	subtitle="Indigo, 3 colors"
	price="$48.00"
	badge="New"
	media={<Image source={{ uri: product.image }} style={{ width: "100%", flex: 1 }} />}
	style={{ width: 240 }}
	onPress={() => router.push(`/products/${product.id}`)}
	onAction={() => cart.add(product.id)}
/>;
import { Image } from "react-native";
import { ProductCardSpotlight } from "@/components/compositions/product-card-spotlight";

<ProductCardSpotlight
	title="Steel bottle"
	subtitle="Sage, 500 ml"
	price="$25.60"
	badge="-20%"
	media={
		<Image
			source={{ uri: product.cutout }}
			resizeMode="contain"
			style={{ width: "100%", height: "100%" }}
		/>
	}
	onPress={() => router.push(`/products/${product.id}`)}
/>;

Use cut-out images (transparent background) with resizeMode="contain": a photo with its own background would fill the inset and lose the effect.

price is a string: format it yourself, currency included, so the card doesn’t decide how your app shows money.

Props

PropTypeDefaultDescription
titlestring—Product name, shown as the card title.
pricestring—Already formatted, currency included: "$24.00". Shown in semibold under the title.
subtitlestring—Secondary line under the title: a color, a size, a brand.
badgestring—Short label in a highlight Badge: "New", "-20%". Sits on the media, or above the title without media.
mediaReactNode—Usually an Image with width: "100%" and flex: 1. With media the card is 3:4: the text keeps its height, the image fills the rest.
actionLabelstring"Add to cart"Label of the action button.
onAction() => void—Shows the full-width action button and handles its press. Without it, there is no button.
onPress() => void—Makes the whole card pressable, to open the product. The button keeps its own press. The card is read as “title, price”.
styleStyleProp<ViewStyle>—Extra styles for the card container, for example a width in a grid.
PropTypeDefaultDescription
titlestring—Product name, on one line under the price.
pricestring—Already formatted, currency included: "$24.00". Shown first, as a headingSm Title.
subtitlestring—Secondary line under the name: a color, a size.
badgestring—Short label in a highlight Badge, on the product: "New", "-20%".
mediaReactNode—Required. A cut-out Image with resizeMode="contain", inset from the card’s edges, in a square. Style it width: "100%" and height: "100%".
actionLabelstring"Add to cart"Label of the action button.
onAction() => void—Shows the full-width action button and handles its press. Without it, there is no button.
onPress() => void—Makes the whole card pressable, to open the product. The button keeps its own press. The card is read as “title, price”.
styleStyleProp<ViewStyle>—Extra styles for the card container, for example a width in a grid.

Built with

  • Card: the surface (outlined, filled for Spotlight), its header, title and description.
  • Badge: the highlight label.
  • Button: the full-width action.
  • Text: the price, and the name in Spotlight.
  • Title: the price in Spotlight.

Used in

No block uses Product Card yet. It is meant for the product grids of the planned Commerce blocks.