Woo Recipes
Recipes are short examples for one job at a time. For complete page composition, start with Product Archive, Single Product, Cart Page, or Checkout Page.
For complete starter route ownership, read
Woo 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.*}:
{#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}
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:
<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>
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:
<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>
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:
<OmeWooAttributeSelector
target='{{"attribute":{attribute}}}'
ui='{{"mode":"color-swatch","aria_label":"Choose {attribute.label}"}}'
behavior='{{"show_swatch_label":false,"unavailable_options":"disabled"}}'
/>
[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;
}
If forest is not mapped, its text remains visible. Do not hide the fallback globally. See Product Purchase 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:
<OmeWooCartItems>
{#slot default}
<OmeWooCartItemImage />
<OmeWooCartItemTitle />
<OmeWooCartItemQuantity />
<OmeWooCartItemRemove />
{/slot}
{#slot empty}
Your cart is empty.
{/slot}
</OmeWooCartItems>
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:
<OmeWooCouponForm />
<OmeWooCouponAppliedList>
{#slot default}
<OmeWooCouponRemoveButton />
{/slot}
</OmeWooCouponAppliedList>
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:
<OmeWooShippingMethodSelector
ui='{{"mode":"button-radio","aria_label":"Choose a shipping method"}}'
content='{{"show_price":true,"price_separator":" - "}}'
/>
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:
<OmeWooCheckoutProvider>
{#slot default}
<OmeWooCheckoutForm>
{#slot default}
<OmeWooBillingAddressForm />
<OmeWooShippingAddressForm />
<OmeWooPaymentMethodSelector />
<OmeWooTermsCheckbox />
<OmeWooCheckoutNotices />
<OmeWooPlaceOrderButton />
{/slot}
</OmeWooCheckoutForm>
{/slot}
</OmeWooCheckoutProvider>
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 for mini-cart drawers, analytics, cart refresh integrations, and checkout instrumentation. Keep event examples there so recipes stay focused on component composition.