Treyza SDK: Product Card Slot
The product card is a slot component: the storefront hands you the product data and the add-to-cart / favorite / compare actions ready-made; you only…
Where: Theme Editor → left panel Components tab → Generate a component with AI → Component type: Product card. Also right panel Product tab → Product Card → Custom cards. For whom: Merchants who want the product list card to go beyond the five built-in options, and the designers who write cards for them In short: The product card is a slot component: the storefront hands you the product data and the add-to-cart / favorite / compare actions ready-made; you only write what the card looks like. The card is produced in the Component Studio, previewed with your real products, becomes selectable in Product Card settings after Publish, and can be shared with the community.
What is a slot component?
A page block (promo strip, FAQ…) is added to a page and stands on its own. A product card instead fills a slot the storefront already draws: in category, search, featured and related product lists the same card is drawn for every product, dozens of times. Therefore the card:
- fetches no data — product, price, image, badges, stock, pre-order and color variants arrive as props,
- writes no actions — add to cart, favorite, compare and quick view come as ready host components,
- renders on the server — Google sees the card in the first HTML, the browser hydrates it,
- never leaves the visitor with an empty box on error; the storefront falls back to the built-in Classic card for that product.
PRODUCT_CARD is the first slot. Other slots such as the cart drawer will be added later with the same mechanism.
Where does a card start?
Choosing Product card as the Component type in the studio opens two paths:
- Start from an official template — Classic, Minimal, Overlay, Editorial and Compact are listed as open source templates. Clicking one creates a copy in your name and builds it; then ask the AI for changes ("make the title bigger", "price in red") or write directly in the Code tab of the right panel (the preview updates as you type, see below). The storefront's built-in five cards are fed from the same templates, so your copy is exactly the production code.
- Generate with AI — describe the card in plain words. The AI knows the product card contract; it does not invent fields, reads the data from props and uses the host buttons.
Both paths go through the same pipeline: code check → build → validation gate (automatic renders with discounted, variant, bundle, out-of-stock, pre-order, imageless and very-long-name products).
Preview, publish and select
- The live preview in the middle panel renders with your store's real products. The desktop/mobile switch narrows the grid.
- Editing the code directly: the Code tab in the right panel is writable for product cards. About a second after you stop typing, the code is compiled on the server through a fast path (code check + browser bundle + CSS; no version, no validation gate) and the preview re-renders; the bar above reads "Preview up to date · N ms". Broken code does not break the preview: the last working state stays and the errors are listed under the code. Save (Ctrl+S) stores the code permanently and starts the persistent build and the validation gate; the storefront still renders only the published version. The code of a card under review or published to the community is locked.
- After an AI turn the new code is previewed through the same fast path before the persistent build finishes; once the build completes, the preview switches to the built version.
- Once built, a Publish button appears at the top. Publishing does not share the card with the community; it only makes it selectable in your store. Later changes do not reach the storefront until you publish again; the storefront always draws the latest published version.
- Use as store card switches the Product Card setting to this card. You can do the same from the right panel: Product → Product Card → Custom cards, which lists your published cards and the ones installed from the community.
- It can also be chosen per block: the Card type setting of the Product List, Curated Strip, Shipping Threshold Progress (suggestions variant) and Empty Search State (recommendations variant) blocks offers Store setting, which follows the Product Card setting; your custom cards are listed below the built-in types. The recommended products on the cart page always use the store card.
- Unpublish makes the card unselectable in your store; code and versions are kept.
- Versions (Status tab): every successful build is a new version; the one published in your store carries the published badge and the one approved for the community the approved badge. Restore this version returns the card to that version's code and bundle under a new version number; the publication does not change, press Publish to put the restored version on the storefront. The current, published and approved versions cannot be deleted; delete the others with the trash icon.
- Wide cards: a card that declares
export const treyza = { contract: 1, slot: "PRODUCT_CARD", wide: true }(like the Compact template) is drawn in a narrow column on the storefront grid, at most four columns on wide screens; the Custom cards list shows a "Wide" badge. - The card appears on the My Components page with a "Product card" badge.
If an unpublished or deleted card stays selected, the storefront silently falls back to Classic; the Product Card setting and the block settings show this with a yellow warning.
Sharing with the community and installing
Share the card from the Status tab with Send to community; the approval gate and locks described in Sharing a Component with the Community apply unchanged. When another merchant sees your card in the Community tab and presses Install, it lands in that store's Custom cards list; an installed card always renders the approved version, even if you change it later.
The data the card receives — ProductCardProps
The card is a single-argument React component taking its types from the @treyza/sdk/slots/product-card entry:
"use client";
import type { ProductCardMeta, ProductCardProps } from "@treyza/sdk/slots/product-card";
export const treyza: ProductCardMeta = { contract: 1, slot: "PRODUCT_CARD" };
export default function MyCard({ product, view, settings, state, actions, labels, ui, format, priority }: ProductCardProps) {
const { Link, Media, AddToCartButton, CompareToggle, FavoriteToggle, ColorSwatches, CardBadgeLayer } = ui;
return (
<div className="group relative flex flex-col overflow-hidden rounded-xl border bg-card">
<Link href={view.url}>
<Media>
<CardBadgeLayer
discountLabel={view.discountLabel}
outOfStockLabel={view.isOutOfStock ? labels.outOfStock : null}
preOrderLabel={product.isPreOrder && !view.isOutOfStock ? labels.preOrder : null}
badges={product.badges}
/>
</Media>
</Link>
<FavoriteToggle className="absolute right-2.5 top-2.5" />
<div className="flex flex-col gap-1.5 p-3">
<Link href={view.url} className="line-clamp-2 text-sm font-medium">{product.name}</Link>
<span className="text-base font-bold">{view.priceLabel}</span>
{view.listPriceLabel && <span className="text-xs line-through text-muted-foreground">{view.listPriceLabel}</span>}
<AddToCartButton className="w-full" />
<CompareToggle className="w-full" />
</div>
</div>
);
}| Field | Contents |
|---|---|
product | Raw product data: name, slug, price.salePrice / listPrice, pictures, gallery (image/video), brand, reviewSummary, stock, noStockContinueBuying, type (BASIC / VARIANT / BUNDLE), bundleSummary, isPreOrder, badges (the merchant's custom badges), colorVariants, mainVariant |
view | Fields derived by the storefront: url, isOutOfStock, isVariant, isBundle, requiresSelection, isPreOrder, discountPercent, discountAmount, discountLabel (per the store's percent/amount setting), priceLabel, listPriceLabel, rating.label, primaryImage, gallery, colorVariants, mainVariantValues, ratioStyle |
settings | currency, locale, discountType, aspectRatio, productUrlPrefix, showVariants, compareEnabled, favoritesEnabled |
state | isFavorite, isCompared, activeColor, addToCartStatus (idle / loading / success) |
actions | addToCart(), toggleFavorite(), toggleCompare(), openQuickView(), selectColor(name) — when you write your own buttons |
labels | Translated texts: addToCart, addedToCart, preOrder, preOrderButton, outOfStock, favoriteAdd, favoriteAdded, compareAdd, compareAdded, quickView, colorOptions, moreColors |
ui | Host components (below) |
format | currency(n) and number(n, options) — formatted for the store locale |
priority | true for first-row cards; ui.Media applies image priority itself |
Host components — ui.*
| Component | What it does |
|---|---|
Link | Link to the product page; the storefront resolves the store's product URL prefix |
Media | Product image: aspect ratio, second image/video on hover, priority loading. children is for the badge layer |
AddToCartButton | Add to cart / pre-order; opens quick view for variant and bundle products, disables itself when out of stock |
CompareToggle | Compare entry; renders nothing when the store setting is off |
FavoriteToggle | Favorite heart; renders nothing when favorites are off |
ColorSwatches | Color dots; a selection changes view.primaryImage, overflow opens quick view |
CardBadgeLayer | Places discount, out-of-stock, pre-order and custom badges in the corners; supports layout="overlay" and density="compact" |
Limits
- Allowed imports:
@treyza/sdk/slots/product-card,@treyza/sdk/ui,@treyza/sdk/primitives,@treyza/sdk/lib/utils,react,@tabler/icons-react(icons by name, one by one),clsx,tailwind-merge. - Forbidden:
@treyza/sdk/data(the card fetches nothing),fetchand any network access,window/document/localStorage/location,eval,dangerouslySetInnerHTML, dynamicimport(),constructor/__proto__/prototypeaccess. The code check rejects these before the build and explains why. configSchemais not used; the card's settings come from the store's Product Card settings.- Prefer theme tokens over fixed colors (
bg-card,text-foreground,text-muted-foreground,bg-primary…) so the card follows the store's color and corner radius settings. - The card renders on the server: no dates, random values or DOM access during the first render.
- Hover layers do not exist on mobile: draw the desktop layer inside
hidden md:blockand separate mobile buttons insidemd:hidden. - Every card should contain one
CompareToggleand oneFavoriteToggle; they hide themselves when off.
FAQ
I changed my card but the storefront does not show it. The card may have been rebuilt but not published; press Publish in the top bar. The storefront draws the latest published version. What you type in the Code tab becomes permanent only after Save; unsaved code is visible only in the studio preview.
I typed in the Code tab, why did the preview not update? Check the error list under the code: code that fails the check or does not compile leaves the preview on the last working state. Once the error is fixed the preview refreshes by itself.
Do the official templates change? No; the Classic…Compact templates are read from the package and always copied. However much you change your copy, the template stays the same and a new copy opens from the original code.
What if the card fails for a single product? Only that product falls back to the built-in Classic card; the rest of the list is unaffected and the error is logged for the store.
Does a card installed from the community update? No; it stays on the author's approved version. A new version requires the author to resubmit and get approval.
Was this page helpful?
Artificial Intelligence (AI) Tools
Artificial intelligence buttons that help you while designing. They suggest icons, write text, generate list items, find images. They all work with a…
Block Entry Animations (Reveal on Scroll)
A block appears with a fade or slide when it scrolls into the visitor's view. The setting sits in the same place on every block; you just pick one of…