Hi @Hitesh_Apps
I’ve analyzed your questions using the Shopify Dev MCP, and this is the advice that’s been generated:
You’ve run into a quirk of how the Refresh (Dawn‑style) cart-drawer expects its data, combined with how you’re manually building parsedState.
The key docs behind this behavior are:
What cart-drawer.renderContents actually expects
In Refresh (and Dawn), cart-drawer.renderContents(parsedState) is written with the assumption that it will receive the same kind of object that Shopify sends back when you use bundled section rendering on /cart/add.js, /cart/change.js, etc.
That object typically looks like:
{
"id": "some-line-item-key-or-variant-id",
"sections": {
"cart-drawer": "<div>...</div>",
"cart-icon-bubble": "<div>...</div>"
},
"sections_url": "/current-page-or-cart-url",
"items": [...],
"item_count": 1,
"token": "..."
}
In your code you’re building this:
function makeParsedState(cart, sections) {
return {
id: cart?.items?.[0]?.variant_id || null,
sections: sections
};
}
This “mostly works” once there’s already something in the cart because the drawer’s DOM and internal state are already in a non‑empty configuration. But:
- You’re not using bundled section rendering from
/cart/add.js
- You’re missing keys like
sections_url, items, item_count, etc.
- You’re guessing the
id from cart.items[0].variant_id, while the theme code often expects the line item key (or at least something very specific from the add/change response)
When the cart starts empty, the drawer’s logic is more sensitive to the initial state and these missing fields. That’s why:
- When the cart already has items → existing DOM/state lets your partial
parsedState work “okay”
- When the cart is empty → the same partial object no longer gives
cart-drawer everything it needs to correctly build the line items
The recommended fix: use bundled section rendering on /cart/add.js
Instead of:
- adding with
/cart/add.js, then
- fetching
/cart.js, then
- fetching
/?sections=cart-drawer,cart-icon-bubble, then
- composing your own
parsedState
…let Shopify build that parsedState for you via bundled section rendering.
From the Cart API reference for bundled section rendering:
You can pass a sections and optional sections_url parameter to /cart/add.js, /cart/change.js, etc. The response JSON will have a sections key with the rendered HTML.
Updated code
Here’s how you can change your code so that the cart drawer always updates correctly, including from an empty cart:
// Add to cart AND ask Shopify to render the necessary sections
fetch('/cart/add.js', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
id: 41736718909515,
quantity: 1,
// request the same sections your drawer uses
sections: 'cart-drawer,cart-icon-bubble',
// ensure sections are rendered in context of current page
sections_url: window.location.pathname
})
})
.then((response) => response.json())
.then((parsedState) => {
const drawer = document.querySelector('cart-drawer');
if (!drawer || typeof drawer.renderContents !== 'function') {
console.error('cart-drawer is not initialized yet.');
return;
}
// parsedState already has the correct structure for Refresh/Dawn
drawer.renderContents(parsedState);
})
.catch((error) => {
console.error('Error adding to cart:', error);
});
//
You’ll need to test out the generated code yourself before pushing to a live store. Also, you’ll likely have a better and more personalised result if you use the Dev MCP in your own IDE, where it will be able to analyze your own theme project. Info on setting that up in this blog post.