> ## Documentation Index
> Fetch the complete documentation index at: https://docs-test.rye.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Components

> Reference for every component in Rewards UI v1. Each entry covers what it is, the install command, and a minimal example.

All components below ship from the `@rye-api` registry at [registry.rye.com](https://registry.rye.com/r/registry.json). Install one at a time as you need them.

***

## `<ProductCard />`

Catalog tile. Renders one product with its image, vendor, name, subtitle, cash price, and an optional points-equivalent. Handles four availability states: `in_stock`, `out_of_stock`, `marketplace_down`, and `image-failed`. Ships with a matching `<ProductCardSkeleton />` for loading.

```bash theme={null}
pnpm dlx shadcn@latest add @rye-api/product-card
```

```tsx theme={null}
import { ProductCard } from "@/components/rye-rewards/product-card";

<ProductCard product={product}>
  <ProductCard.Image />
  <ProductCard.Info />
</ProductCard>
```

***

## `<ProductDetails />`

Compound PDP. Two-column layout with image gallery (caps at 8 thumbs + overflow caption), variant pickers (swatches / grid / cards, adaptive column count for long labels), inline revalidation alert for sold-out variants, quantity stepper, and a redeem CTA. Ships with `<ProductDetailsSkeleton />`.

```bash theme={null}
pnpm dlx shadcn@latest add @rye-api/product-details
```

```tsx theme={null}
import { ProductDetails } from "@/components/rye-rewards/product-details";

<ProductDetails
  data={pdpData}
  selection={selection}
  onSelectionChange={onSelectionChange}
>
  <ProductDetails.Breadcrumbs items={breadcrumbs} />
  <ProductDetails.Gallery />
  <ProductDetails.Header />
  <ProductDetails.Variants />
  <ProductDetails.Quantity value={qty} onChange={setQty} />
  <ProductDetails.Redeem onClick={onRedeem}>
    Redeem with points · {formatted}
  </ProductDetails.Redeem>
</ProductDetails>
```

The redeem CTA takes children, not a label prop — pass any button content (including the standard `disabled` boolean to lock it).

***

## `<VariantSelector />`

Standalone variant picker. The same swatches / grid / cards picker that lives inside `<ProductDetails.Variants />`, exposed for reuse — drop it into a `<PaymentSheet />` flow or any other surface that needs variant selection without the full PDP.

```bash theme={null}
pnpm dlx shadcn@latest add @rye-api/variant-selector
```

```tsx theme={null}
import { VariantSelector } from "@/components/rye-rewards/variant-selector";

<VariantSelector
  dimensions={dimensions}
  selection={selection}
  onSelectionChange={onSelectionChange}
/>
```

***

## `<PayWithPoints />`

Composable redemption slot. `<Header />` shows the balance pill, `<Slider />` is a keyboard-accessible range slider (arrow keys + Home / End) for picking how many points to apply, and `<Summary />` surfaces the after-redemption balance plus a partial-coverage info card when the balance can't cover the order. Enabling/disabling points is a consumer concern — conditionally render based on your own state.

```bash theme={null}
pnpm dlx shadcn@latest add @rye-api/pay-with-points
```

```tsx theme={null}
import { PayWithPoints } from "@/components/rye-rewards/pay-with-points";

<PayWithPoints
  balance={balance}
  maxApplicable={maxApplicable}
  applied={applied}
  onAppliedChange={setApplied}
>
  <PayWithPoints.Header rateLabel="100 pts = $1.00" />
  <PayWithPoints.Slider />
  <PayWithPoints.Summary orderTotal={orderTotal} />
</PayWithPoints>
```

***

## `<PaymentSheet />`

Compound checkout sheet. Slot-based — pick the subcomponents you need per state. Covers cash + member-benefit, mixed tender, full points, and five error variants (variant gone, no shipping, unpriceable, marketplace down, card declined).

```bash theme={null}
pnpm dlx shadcn@latest add @rye-api/payment-sheet
```

```tsx theme={null}
import { PaymentSheet } from "@/components/rye-rewards/payment-sheet";

<PaymentSheet>
  <PaymentSheet.Header title="Confirm redemption" subtitle="One item · Standard delivery" />
  <PaymentSheet.Item item={item} />
  <PaymentSheet.Shipping buyer={buyer} onEdit={onEditAddress} />
  <PaymentSheet.CostBreakdown lines={costLines} total={total} />
  <PaymentSheet.Confirm onClick={onConfirm}>Confirm · {total}</PaymentSheet.Confirm>
</PaymentSheet>
```

`<PaymentSheet.Shipping />` takes the canonical `Buyer` shape from `checkout-intents/resources` — pass intent responses through without remapping.

***

## `<OrderTracking />`

Compound post-purchase view covering 8 lifecycle states: `placed`, `processing`, `shipped`, `out_for_delivery`, `delivered`, `cancelled`, `refunded`, `stuck_under_investigation`. Timeline is semantic `<ol>` / `<li>` with `aria-current="step"`. `<InvestigationCard />` carries `role="status"` + `aria-live="polite"` so screen readers announce status updates.

```bash theme={null}
pnpm dlx shadcn@latest add @rye-api/order-tracking
```

```tsx theme={null}
import { OrderTracking } from "@/components/rye-rewards/order-tracking";

<OrderTracking>
  <OrderTracking.Header orderId="#RW-3CCF7768" pill={statusPill} />
  <OrderTracking.StatusCard eyebrow="Arriving today" title="Between 11:00 AM – 6:00 PM" />
  <OrderTracking.Timeline steps={timelineSteps} />
  <OrderTracking.Item name="..." imageUrl="..." price={price} />
  <OrderTracking.ActionsCard actions={actions} />
</OrderTracking>
```

Icon props throughout (`StatusPill.icon`, `Callout.icon`, `Action.leadingIcon` / `trailingIcon`) accept any `React.ReactNode` — pass lucide elements or your own SVGs.

***

## `<AddressForm />`

Write-side companion to `<PaymentSheet.Shipping />`. Compound API produces the same `Buyer` shape `Shipping` consumes. Validation is consumer-owned — pass `fieldErrors` keyed by `Buyer` field name and the component handles `aria-invalid` + error message rendering. Plug in zod, react-hook-form, or roll your own.

```bash theme={null}
pnpm dlx shadcn@latest add @rye-api/address-form
```

```tsx theme={null}
import { AddressForm } from "@/components/rye-rewards/address-form";

<AddressForm
  value={buyer}
  onChange={setBuyer}
  fieldErrors={errors}
  onSubmit={handleSubmit}
>
  <AddressForm.Name />
  <AddressForm.Address />
  <AddressForm.Region />
  <AddressForm.Contact />
  <AddressForm.Submit>Save address</AddressForm.Submit>
</AddressForm>
```

Browser-autofill ready via canonical `autoComplete` attrs (`given-name`, `family-name`, `address-line1`, `postal-code`, `country`, `email`, `tel`).

***

## Shared utilities

Each component depends on a small set of shared helpers that the shadcn CLI auto-installs:

* **`lib/format.ts`** — exports `formatMoney(money)` and `formatPoints(points)`. Edit this file to localize currency formatting or change the points label (e.g. `"X,XXX LoC pts"` for branded rewards). One edit affects every component that displays money or points.
* **`lib/utils.ts`** — the standard shadcn `cn()` className helper.
* **`components/rye-rewards/types/product.ts`** — canonical `Product` / `Money` / `Marketplace` / `ProductAvailability` types.
* **`components/rye-rewards/types/pdp.ts`** — `ProductDetailsData` plus the shared variant types used by `ProductDetails` and `VariantSelector`.

## Source

[github.com/rye-com/rewards-ui](https://github.com/rye-com/rewards-ui) (MIT). Every component file is short and editable — when defaults don't fit, fork the source.
