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

# React components

> shadcn-style composition primitives for @quickshops/sdk/react — Storefront.Product, BuyButton, and more using your theme CSS variables.

# React components

Optional UI for Next.js / React apps that already use [`useStore()`](/sdk/installation) on the **server**.

```bash theme={null}
npm install @quickshops/sdk react
```

Requires **`@quickshops/sdk@1.1.0+`** for the `/react` export.

## v1 scope (SSR)

Custom storefronts are **SSR-first** for SEO. There is **no publishable / browser API key** in v1.

| Do                                                          | Don’t                                             |
| ----------------------------------------------------------- | ------------------------------------------------- |
| Load catalog in Server Components with `useStore()`         | Fetch `api.quickshops.app` from the browser       |
| Pass products + Server Actions into `@quickshops/sdk/react` | Put `qk_` / `HEADLESS_API_KEY` in `NEXT_PUBLIC_*` |
| Keep checkout on the server (`buyNow` → `redirect`)         | Invent a client-side Speakeasy client             |

## Theming (parent CSS variables)

Components are **shadcn-style**: Tailwind utility classes + `data-slot` attributes that read **your** theme tokens.

They expect the usual shadcn / Tailwind v4 CSS variables on `:root` (or your theme), for example:

* `--background`, `--foreground`
* `--card`, `--card-foreground`
* `--primary`, `--primary-foreground`
* `--secondary`, `--muted`, `--accent`, `--border`, `--input`, `--ring`

If your Lovable / v0 / Next app already uses shadcn, **no extra theme setup** — pass `className` to override. Override any part with `className` (merged via `tailwind-merge`).

## Composition primitives

Prefer composing slots over boolean props:

```tsx theme={null}
import { Storefront, toStoreProducts } from "@quickshops/sdk/react";

<Storefront.Provider
  products={toStoreProducts(products)}
  actions={{ buy: buyProduct }}
>
  <Storefront.Grid>
    {products.map((product) => (
      <Storefront.Product key={product.id} product={product}>
        <Storefront.ProductImage />
        <Storefront.ProductHeader>
          <Storefront.ProductTitle />
          <Storefront.ProductDescription />
        </Storefront.ProductHeader>
        <Storefront.ProductContent>
          <Storefront.ProductPrice />
        </Storefront.ProductContent>
        <Storefront.ProductFooter>
          <Storefront.BuyButton />
        </Storefront.ProductFooter>
      </Storefront.Product>
    ))}
  </Storefront.Grid>
</Storefront.Provider>
```

### Available surface

| Export                                               | Kind      | Purpose                                            |
| ---------------------------------------------------- | --------- | -------------------------------------------------- |
| `Storefront.Provider`                                | Context   | Inject `products` + `actions` (`buy`, `addToCart`) |
| `Storefront.Grid`                                    | Layout    | Responsive product grid                            |
| `Storefront.Product`                                 | Root      | Product card shell + product context               |
| `Storefront.ProductImage`                            | Slot      | Cover image                                        |
| `Storefront.ProductHeader` / `Title` / `Description` | Slots     | Text block                                         |
| `Storefront.ProductContent` / `Price`                | Slots     | Body / price                                       |
| `Storefront.ProductFooter`                           | Slot      | Actions row                                        |
| `Storefront.BuyButton`                               | Action    | Calls `actions.buy` (or `buy` prop)                |
| `Storefront.AddToCartButton`                         | Action    | Calls `actions.addToCart`                          |
| `Storefront.Button`                                  | Primitive | shadcn-like button (`variant` / `size`)            |
| `Storefront.ProductCard`                             | Recipe    | Default composition (image → title → price → buy)  |
| `CheckoutSuccess` / `CheckoutSuccessParts.*`         | Compound  | Success page slots                                 |
| `toStoreProducts`                                    | Util      | Normalize `loadCatalog()` products                 |
| `formatMoney` / `productIdOf`                        | Util      | Formatting helpers                                 |

Flat named exports (`BuyButton`, `ProductCard`, …) are also available.

## Example: catalog + buy now

```ts theme={null}
// app/actions.ts
"use server";

import { redirect } from "next/navigation";
import { useStore } from "@quickshops/sdk";

export async function buyProduct(productId: string) {
  const store = useStore();
  const { url } = await store.buyNow({ productId });
  redirect(url);
}
```

```tsx theme={null}
// app/page.tsx — Server Component
import { Storefront, toStoreProducts } from "@quickshops/sdk/react";
import { useStore } from "@quickshops/sdk";
import { buyProduct } from "./actions";

export default async function ShopPage() {
  const store = useStore();
  const { products } = await store.loadCatalog();
  const list = toStoreProducts(products);

  return (
    <main>
      <h1>Shop</h1>
      <Storefront.Provider products={list} actions={{ buy: buyProduct }}>
        <Storefront.Grid />
      </Storefront.Provider>
    </main>
  );
}
```

`Storefront.Grid` with no children renders a `ProductCard` per product. Compose slots yourself when you need a custom layout.

## Example: success page

```tsx theme={null}
import { CheckoutSuccessParts } from "@quickshops/sdk/react";

<CheckoutSuccessParts.Root session={session}>
  <CheckoutSuccessParts.Title />
  <CheckoutSuccessParts.Email />
  <CheckoutSuccessParts.Total />
  <CheckoutSuccessParts.LineItems />
</CheckoutSuccessParts.Root>
```

Or the recipe: `<CheckoutSuccess session={session} />`.

## Related

* [TypeScript SDK](/sdk/installation) — `useStore()`
* [One-prompt DIY](/sdk/one-prompt-storefront)
* [Framework guides](/sdk/framework-guides)
