Skip to main content

Add Item to Order

Headless component for managing adding items to an order with quantity selection and add-to-cart functionality.

Purpose

This library provides a comprehensive system for adding products to the shopping cart, including quantity selection and add-to-cart functionality. It's designed as a headless component that provides all the logic while allowing complete UI customization. The component manages state for whether an item is in the cart, handles loading states, and provides callbacks for custom validation logic before adding or adjusting items.

Features

  • Add items to order with quantity selection
  • Adjust quantity of existing order lines
  • Customizable callbacks for pre-add and pre-adjust validation
  • Support for render props and regular children patterns
  • Optimistic updates for better UX
  • Automatic cart state management
  • Cross-platform support (web and native via asChild pattern)
  • Quantity controls with min/max/step constraints

Installation

npm install @haus-storefront-react/add-item-to-order

Note: This is not a public package. Contact the Haus Tech Team for access.

API Reference

AddItemToOrder.Root

Main container component that provides add-to-cart context and state. Can be used with either regular children or a render prop function. Must wrap all other AddItemToOrder components.

Props

PropTypeRequiredDefaultDescription
productVariantIdstringYes-The ID of the product variant to add to the order
callbacksCallbacksNoundefinedOptional callbacks for custom logic before operations
modifyData(data: Order) => OrderNoundefinedOptional function to modify the order before cart checks
childrenChildrenProps<AddItemToOrderContextValue>No-Either React nodes or a function that receives the context value
asChildbooleanNofalseWhen true, merges props with the child component

Context Value (when using render prop)

The render prop function receives an object with the following properties:

PropertyTypeDescription
productVariantIdstringThe ID of the product variant
isInCartboolean | undefinedWhether the item is in the cart (undefined while loading)
isLoadingbooleanWhether an add or adjust-quantity operation is in progress
errorError | nullError from add-to-cart or adjust quantity (e.g. INSUFFICIENT_STOCK_ERROR)
addItemToOrder(quantity: number) => Promise<Maybe<Order>>Function to add item to order
orderLineIdstring | undefinedThe ID of the order line if item is in cart
adjustOrderLine(orderLineId: string, quantity: number) => Promise<Order>Function to adjust quantity for an existing order line
orderLinesOrderLine[] | undefinedCurrent order lines from the active order
callbacksCallbacks | undefinedThe callbacks passed to the Root component
modifyData((data: Order) => Order) | undefinedThe modifyData function passed to the Root component

Callbacks Object

interface Callbacks {
preAdd?: (productVariantId: string, quantity: number) => Promise<void>
preAdjust?: (orderLineId: string, quantity: number) => Promise<void>
}

AddItemToOrder.Button

Button component for adding an item to the order. Must be used within AddItemToOrder.Root. Supports the asChild pattern for cross-platform compatibility.

Props

PropTypeRequiredDefaultDescription
asChildbooleanNofalseWhen true, merges props with the child component
childrenReactNodeNo-Button content
...propsWebButtonPropsNo-Additional button props (onClick, disabled, etc.)

AddItemToOrder.Quantity.Root

Quantity controls container component. Must be used within AddItemToOrder.Root. Renders quantity controls for an existing order line.

Sub-components:

  • AddItemToOrder.Quantity.Decrement - Button to decrease quantity (accepts standard button props and asChild)
  • AddItemToOrder.Quantity.Input - Input field for displaying and editing quantity (accepts standard input props)
  • AddItemToOrder.Quantity.Increment - Button to increase quantity (accepts standard button props and asChild)

Props

PropTypeRequiredDefaultDescription
minnumberNo0Minimum quantity
maxnumberNoundefinedMaximum quantity
stepnumberNo1Step size for quantity changes
asChildbooleanNofalseWhen true, merges props with the child component
childrenReactNodeNo-Quantity control children (Decrement, Input, Increment)

useAddItemToOrderProps

Hook that powers the AddItemToOrder compound components. It exposes add-to-cart state, mutation helpers, and prebuilt button props for custom implementations.

Parameters

ParameterTypeRequiredDescription
productVariantIdstringYesProduct variant ID to manage in cart
callbacks{ preAdd?: ...; preAdjust?: ...}NoOptional async callbacks executed before add/adjust operations
modifyData(data: Order) => OrderNoOptional function to normalize order data before in-cart evaluation

Returns

Return ValueTypeDescription
addItemToOrder(quantity: number) => Promise<Maybe<Order>>Function to add the variant with specified quantity
errorError | nullMutation error state
isLoadingbooleanLoading state for add operation
getButtonProps() => { onClick: () => void; disabled: boolean; ... }Helper for wiring an "Add to cart" button
isInCartboolean | undefinedWhether the product variant currently exists in cart

Basic Usage

Simple Component

import { AddItemToOrder } from '@haus-storefront-react/add-item-to-order'

function MyComponent({ product }) {
const defaultVariant = product.variants[0]

return (
<div>
<AddItemToOrder.Root productVariantId={defaultVariant.id}>
{({ isInCart, isLoading, error }) => (
<>
{!isInCart && (
<AddItemToOrder.Button>
{isLoading ? 'Adding...' : 'Add to Cart'}
</AddItemToOrder.Button>
)}
{isInCart && (
<AddItemToOrder.Quantity.Root>
<AddItemToOrder.Quantity.Decrement>
-
</AddItemToOrder.Quantity.Decrement>
<AddItemToOrder.Quantity.Input />
<AddItemToOrder.Quantity.Increment>
+
</AddItemToOrder.Quantity.Increment>
</AddItemToOrder.Quantity.Root>
)}
{error && <div>Error: {error.message}</div>}
</>
)}
</AddItemToOrder.Root>
</div>
)
}

Basic Hook Usage

import { AddItemToOrder } from '@haus-storefront-react/add-item-to-order'

function MyComponent({ productVariantId }) {
return (
<AddItemToOrder.Root productVariantId={productVariantId}>
{({ isInCart, isLoading, error, addItemToOrder }) => (
<div>
{!isInCart && (
<button onClick={() => addItemToOrder(1)} disabled={isLoading}>
{isLoading ? 'Adding...' : 'Add to Cart'}
</button>
)}
{isInCart && <div>Item is in cart</div>}
{error && <div>Error: {error.message}</div>}
</div>
)}
</AddItemToOrder.Root>
)
}

Advanced Usage

Custom Callbacks

<AddItemToOrder.Root
productVariantId='variant-123'
callbacks={{
preAdd: async (productVariantId, quantity) => {
// Custom validation logic before adding
if (quantity > 10) {
throw new Error('Maximum quantity is 10')
}
// Optional: Show confirmation dialog
const confirmed = await confirm('Add to cart?')
if (!confirmed) {
throw new Error('Cancelled by user')
}
},
preAdjust: async (orderLineId, quantity) => {
// Custom logic before adjusting quantity
console.log(
'Adjusting order line:',
orderLineId,
'to quantity:',
quantity,
)
},
}}
>
{/* Component content */}
</AddItemToOrder.Root>

Modifying Order Data with modifyData

Use modifyData to transform the order before the component derives its state. Useful for filtering duplicate productVariant IDs or excluding certain lines.

<AddItemToOrder.Root
productVariantId={variant.id}
modifyData={(order) => ({
...order,
// Example: exclude gift lines from cart state
lines: order.lines.filter((line) => !line.customFields?.gift),
})}
>
{/* Component content */}
</AddItemToOrder.Root>

Component Configuration

import { AddItemToOrder } from '@haus-storefront-react/add-item-to-order'

function AdvancedComponent({ productVariantId }) {
return (
<AddItemToOrder.Root
productVariantId={productVariantId}
callbacks={{
preAdd: async (productVariantId, quantity) => {
if (quantity > 10) {
throw new Error('Maximum quantity is 10')
}
},
preAdjust: async (orderLineId, quantity) => {
console.log('Adjusting order line:',
orderLineId,
'to quantity:',
quantity,
)
},
}}
modifyData={(order) => ({
...order,
lines: order.lines.filter((line) => !line.customFields?.gift),
})}
>
{({ isInCart, isLoading, error }) => (
<div className='advanced-add-to-cart'>
{!isInCart ? (
<AddItemToOrder.Button>
{isLoading ? 'Adding...' : 'Add to Cart'}
</AddItemToOrder.Button>
) : (
<AddItemToOrder.Quantity.Root min={0} max={10} step={1}>
<AddItemToOrder.Quantity.Decrement>
-
</AddItemToOrder.Quantity.Decrement>
<AddItemToOrder.Quantity.Input />
<AddItemToOrder.Quantity.Increment>
+
</AddItemToOrder.Quantity.Increment>
</AddItemToOrder.Quantity.Root>
)}

{error && <div className='error-message'>{error.message}</div>}
</div>
)}
</AddItemToOrder.Root>
)
}

Made with ❤️ by Haus Tech Team