Hydrogen’s bundles recipe adds visual indicators and data handling for Shopify product bundles across the storefront — product pages, collection listings, cart, and home page recommendations.
Prerequisites
The Shopify Bundles app must be installed in the store’s admin panel. The store must meet Shopify’s eligibility requirements, and at least one bundle must be created before the storefront changes take effect.
Bundle Detection
Bundles are detected via the requiresComponents boolean on ProductVariant.
The recipe queries this through an aliased field to keep bundle logic separate
from variant selection:
isBundle: selectedOrFirstAvailableVariant(
ignoreUnknownOptions: true
selectedOptions: { name: "", value: "" }
) {
...on ProductVariant {
requiresComponents
components(first: 100) {
nodes {
productVariant { ...ProductVariant }
quantity
}
}
groupedBy(first: 100) {
nodes { id }
}
}
}At runtime: const isBundle = Boolean(product.isBundle?.requiresComponents);
Components
BundleBadge
A green absolute-positioned label (“BUNDLE”) rendered on product images and cart
line items. Requires a parent with position: relative.
BundledVariants
Renders the list of products contained in a bundle. Each row shows a thumbnail,
product/variant title, and quantity, linking to the individual product page.
Accepts variants: ProductVariantComponent[] from Hydrogen’s storefront API
types.
Files Modified
| File | Change |
|---|---|
app/components/BundleBadge.tsx | New — badge component |
app/components/BundledVariants.tsx | New — bundled variants list |
app/routes/products.$handle.tsx | Queries isBundle, renders BundledVariants, passes isBundle to ProductImage and ProductForm |
app/routes/collections.$handle.tsx | Queries isBundle in PRODUCT_ITEM_FRAGMENT |
app/lib/fragments.ts | Adds requiresComponents, components, groupedBy to cart fragments |
app/components/CartLineItem.tsx | Shows BundleBadge for bundle line items |
app/components/ProductForm.tsx | Button text: “Add bundle to cart” vs “Add to cart” |
app/components/ProductImage.tsx | Shows BundleBadge overlay when isBundle |
app/components/ProductItem.tsx | Shows BundleBadge on product cards in listings |
app/routes/_index.tsx | Adds maxVariantPrice to recommended products query |
app/styles/app.css | Adds position: relative to .product-image |
Adapting to Non-Skeleton Projects
The recipe steps target the Hydrogen skeleton template. When adapting to a custom project:
- File names and paths will differ — map each skeleton file to its equivalent in your project structure.
- Steps are not strictly ordered; dependencies between steps (e.g., fragments must exist before components can query them) determine execution order.
- Never edit generated
.d.tsfiles directly — runnpm run codegen(if available) to regenerate them after GraphQL changes.
Key Patterns
requiresComponentsas detection flag — single boolean onProductVariantthat identifies bundles.- Aliased query field (
isBundle) — keeps bundle logic isolated from primary variant selection. componentsconnection — providesProductVariantComponentnodes with variant data and quantity for rendering bundled items.- Badge overlay —
BundleBadgeuses absolute positioning; parent containers must setposition: relative. - Conditional button text —
ProductFormadjusts CTA copy based onisBundleprop.
Troubleshooting
| Issue | Solution |
|---|---|
| No bundles visible on storefront | Install Shopify Bundles app and create bundles in admin |
| No badges on product pages | Verify PRODUCT_FRAGMENT includes the isBundle alias and BundledVariants is rendered |
| No badges in cart | Verify CART_QUERY_FRAGMENT includes requiresComponents and components |
See Also
- shopify-bundles-api — Bundles API: fixed vs customized, Admin API mutations, limits, admin UI
- hydrogen-development-training — Hydrogen learning curriculum
- Hydrogen Bundles Recipe (source)
- Hydrogen Bundles LLM Prompt (source)