Package: @shopify/hydrogen@0.0.0-preview-8a708a8-20260708155454 (framework-agnostic preview)
Summary
When a product form submits an add-to-cart, buildAddToCartDetail (src/core/product/product-form.ts, shipped as dist/core/product/product-form.mjs) builds the event detail the cart store uses to construct the optimistic line:
function buildAddToCartDetail(context) {
const { selectedVariant } = context.observable.state;
if (!selectedVariant) return void 0;
return { products: [{
id: selectedVariant.id,
title: selectedVariant.title,
product: selectedVariant.product ? { title: selectedVariant.product.title } : void 0,
image: selectedVariant.image,
price: selectedVariant.price
}] };
}
selectedVariant.selectedOptions is available at this point (the product store already tracks it), but it isn't included, so the optimistic line's merchandise has no selectedOptions.
Why it matters
A cart line component that renders options as Size: Large from merchandise.selectedOptions renders correctly for resolved lines but has nothing to render during the optimistic window. The only stand-in is merchandise.title (the variant title, e.g. Large / Square), which loses the option names. The result is a visible label flicker when the mutation resolves: Large / Square becomes Size: Large · Format: Square. The workaround is to render values only everywhere, dropping option names from resolved lines too.
There's also no userland escape hatch: useCartForm().formProps() calls store.handleFormSubmit(e.nativeEvent) without exposing the eventDetail parameter, and useProductForm builds the detail internally, so an app can't augment the payload itself.
Suggested fix
Include selectedOptions: selectedVariant.selectedOptions in the buildAddToCartDetail product payload (the cart store already spreads the whole product detail into optimistic merchandise, so no consumer-side change would be needed). Alternatively or additionally, let formProps/handleFormSubmit accept a custom event detail so apps can enrich the optimistic line themselves.
Package:
@shopify/hydrogen@0.0.0-preview-8a708a8-20260708155454(framework-agnostic preview)Summary
When a product form submits an add-to-cart,
buildAddToCartDetail(src/core/product/product-form.ts, shipped asdist/core/product/product-form.mjs) builds the event detail the cart store uses to construct the optimistic line:selectedVariant.selectedOptionsis available at this point (the product store already tracks it), but it isn't included, so the optimistic line'smerchandisehas noselectedOptions.Why it matters
A cart line component that renders options as
Size: Largefrommerchandise.selectedOptionsrenders correctly for resolved lines but has nothing to render during the optimistic window. The only stand-in ismerchandise.title(the variant title, e.g.Large / Square), which loses the option names. The result is a visible label flicker when the mutation resolves:Large / SquarebecomesSize: Large · Format: Square. The workaround is to render values only everywhere, dropping option names from resolved lines too.There's also no userland escape hatch:
useCartForm().formProps()callsstore.handleFormSubmit(e.nativeEvent)without exposing theeventDetailparameter, anduseProductFormbuilds the detail internally, so an app can't augment the payload itself.Suggested fix
Include
selectedOptions: selectedVariant.selectedOptionsin thebuildAddToCartDetailproduct payload (the cart store already spreads the whole product detail into optimisticmerchandise, so no consumer-side change would be needed). Alternatively or additionally, letformProps/handleFormSubmitaccept a custom event detail so apps can enrich the optimistic line themselves.