# Woo Recipes

> Short task-focused Woo examples for product cards, quantity controls, variable products, cart rows, coupons, shipping, checkout, and events.

# Woo Recipes

Recipes are short examples for one job at a time. For complete page composition, start with [Product Archive](/woo/flows/product-archive), [Single Product](/woo/flows/single-product), [Cart Page](/woo/flows/cart-page), [Checkout Page](/woo/flows/checkout-page), [My Account Page](/woo/flows/my-account-page), or [Order Received Page](/woo/flows/order-received-page).

For complete starter route ownership, read
[Woo Template Integration Contract](/woo/flows/template-integration-contract)
before composing individual recipes. It covers the `archive-product`,
`single-product`, cart, checkout, order confirmation, taxonomy archive, and Woo
page option contract that these component recipes assume.

## Product Archive Card

Use a product loop and bind each card with `{item.*}`:

<CodeExample title="Product archive purchase card" language="text">
{`{#loop products as item}
  <OmeWooAddToCartForm product='{{"product_id":"{item.id}","product_type":"{item.omewoo.product.type}"}}'>
    {#slot default}
      <OmeWooAddToCartButton behavior='{{"mode":"counter","trigger":"form_submit"}}' />
    {/slot}
  </OmeWooAddToCartForm>
{/loop}`}
</CodeExample>

Why it works: the form owns product ID/type and form submission; the button is a submit control inside the form. Add `CartCount` above the loop when the archive should show a live cart count.

## Single Product Quantity

Use `{this.*}` on a single product template and set button quantity bounds:

<CodeExample title="Single product form with quantity bounds" language="jsx">
{`<OmeWooAddToCartForm product='{{"product_id":"{this.id}","product_type":"{this.omewoo.product.type}"}}'>
  {#slot default}
    <OmeWooAddToCartButton
      behavior='{{"mode":"counter","trigger":"form_submit"}}'
      quantity='{{"min":"1","max":"3","default":"2"}}'
    />
  {/slot}
</OmeWooAddToCartForm>`}
</CodeExample>

Why it works: `counter` mode renders a quantity input, and the form-submit trigger keeps quantity and product data on the parent form payload.

## Variable Product Selector

Loop over product attributes and bind each `AttributeSelector` to the current attribute object:

<CodeExample title="Variation attribute selectors inside a purchase form" language="jsx">
{`<OmeWooAddToCartForm product='{{"product_id":"{this.id}","product_type":"{this.omewoo.product.type}","variants":{this.omewoo.variants}}}'>
  {#slot default}
    {#loop this.omewoo.attributes as attribute}
      <OmeWooAttributeSelector
        target='{{"attribute":{attribute}}}'
        ui='{{"mode":"radio","aria_label":"Choose {attribute.label}"}}'
      />
    {/loop}
    <OmeWooAddToCartButton behavior='{{"mode":"counter","trigger":"form_submit"}}' />
  {/slot}
</OmeWooAddToCartForm>`}
</CodeExample>

Why it works: the selector writes selected variation attribute state into the purchase form. The form blocks submit until required variation options are selected, and unavailable options do not select. For products with more than one variation attribute, `product.variants` lets the runtime resolve the final `variation_id` from the complete selected combination, such as `Color = Blue` plus `Size = Small`.

## Color Swatch Selector

Switch only the appropriate attribute to swatches in Etch, then map exact option slugs in scoped CSS:

<CodeExample title="Color swatch attribute selector" language="jsx">
	{`<OmeWooAttributeSelector
  target='{{"attribute":{attribute}}}'
  ui='{{"mode":"color-swatch","aria_label":"Choose {attribute.label}"}}'
  behavior='{{"show_swatch_label":false,"unavailable_options":"disabled"}}'
/>`}
</CodeExample>

<CodeExample title="CSS-first swatch mapping" language="css">
	{`[data-ome-woo-attribute-selector][data-ome-ui-choice-mode="color-swatch"]
  [data-ome-value="forest"] {
  --ome-woo-swatch-color: #234f32;
  --ome-woo-swatch-fallback-display: none;
}`}
</CodeExample>

If `forest` is not mapped, its text remains visible. Do not hide the fallback globally. See [Product Purchase](/woo/component-families/product-purchase#color-and-image-swatches) for image mappings, light-color borders, keyboard behavior, and stable Woo variation-image rules.

## Cart Rows and Empty State

Place cart item atoms inside the `CartItems` default slot and empty content inside the `empty` slot:

<CodeExample title="Cart item rows with empty fallback" language="jsx">
{`<OmeWooCartItems>
  {#slot default}
    <OmeWooCartItemImage />
    <OmeWooCartItemTitle />
    <OmeWooCartItemQuantity />
    <OmeWooCartItemRemove />
  {/slot}
  {#slot empty}
    Your cart is empty.
  {/slot}
</OmeWooCartItems>`}
</CodeExample>

Why it works: `CartItems` owns the repeated cart row. The item atoms read the current row that `CartItems` hydrates.

## Coupons

Use `CouponForm` to apply codes, `CouponAppliedList` to render current coupons, and `CouponRemoveButton` inside the coupon row:

<CodeExample title="Coupon apply and remove" language="jsx">
{`<OmeWooCouponForm />

<OmeWooCouponAppliedList>
  {#slot default}
    <OmeWooCouponRemoveButton />
  {/slot}
</OmeWooCouponAppliedList>`}
</CodeExample>

Why it works: `CouponRemoveButton` reads the coupon code from the row generated by `CouponAppliedList`.

## Shipping Methods

Use `ShippingMethodSelector` wherever cart shipping selection should be available:

<CodeExample title="Shipping method selector in button-radio mode" language="jsx">
{`<OmeWooShippingMethodSelector
  ui='{{"mode":"button-radio","aria_label":"Choose a shipping method"}}'
  content='{{"show_price":true,"price_separator":" - "}}'
/>`}
</CodeExample>

Why it works: the selector uses package-aware rate values, so Woo can distinguish shipping rates across packages.

## Checkout Shell

Use a provider, a form, address forms, selectors, terms, notices, and place order:

<CodeExample title="Checkout provider and form shell" language="jsx">
{`<OmeWooCheckoutProvider>
  {#slot default}
    <OmeWooCheckoutForm>
      {#slot default}
        <OmeWooBillingAddressForm />
        <OmeWooShippingAddressForm />
        <OmeWooPaymentMethodSelector />
        <OmeWooTermsCheckbox />
        <OmeWooCheckoutNotices />
        <OmeWooPlaceOrderButton />
      {/slot}
    </OmeWooCheckoutForm>
  {/slot}
</OmeWooCheckoutProvider>`}
</CodeExample>

Why it works: `CheckoutProvider` creates the checkout scope, `CheckoutForm` owns serialization and submission, and `PlaceOrderButton` submits the parent form.

## Native Hook Compatibility

Use the same components as normal. The important point is that Store API requests still run Woo hooks:

- Add-to-cart validation can block the Etch form and render a Woo notice.
- Add-to-cart hooks can inject cart item data.
- Pricing hooks can change totals rendered by cart and order summary components.
- Checkout hooks can update Store API orders and payment context.

## Event Integrations

Use [Woo Custom Events](/woo/custom-events) for mini-cart drawers, analytics, cart refresh integrations, and checkout instrumentation. Keep event examples there so recipes stay focused on component composition.
