Peregrinedocs

Cart

A slide-out drawer or a full cart page — one setting decides, and nothing breaks when you change your mind. Quantity rules per line, order notes, a three-milestone rewards bar and optional cross-sell recommendations, all computed from your store's real data.

Drawer or page — one setting

Theme settings → Cart → Cart type chooses the experience. Drawer (the default) slides the cart out over the page whenever something is added or the header cart icon is tapped, so shoppers never lose their place. Page sends them to the cart page instead — the calmer pattern for stores with considered, few-item orders.

The cart page exists in both modes and is always reachable at /cart — the drawer offers a "View cart page" link to it, up beside the drawer's heading, and shoppers browsing without JavaScript land there automatically, where quantity edits, removal and checkout all work as a plain form. Switching modes can never strand anyone: in page mode none of the drawer's markup or scripts are loaded at all.

In page mode a second setting, After adding to cart, chooses whether shoppers stay on the product page (with the button confirming the add) or go straight to the cart.

Quick add is the exception, deliberately. Adding from a collection grid always ends at the cart — the drawer in drawer mode, the cart page otherwise — whatever that setting says. Quick add's pop-up closes on a successful add, and a pop-up that vanishes leaving the shopper exactly where they were reads as a failed add rather than a successful one.

Line items

Both surfaces render the same line items, so they can never disagree. Each line carries the product image, title, options, price and any discounts Shopify has applied — line-level and order-level discounts both show with their names and amounts, read from Shopify's own answer rather than recalculated.

Quantity rules follow every line. If a product sells in threes or has a minimum of six, the cart's stepper honours the same rules as the product page — including stock ceilings where you track inventory and don't allow overselling. Stepping below the minimum removes the line rather than stranding an unbuyable quantity.

Unit prices show where they apply (a Theme Store requirement), gift-card recipient details travel with their line, and internal properties (those an app prefixes with an underscore, or empty values) are never shown to shoppers.

A line is two rows, not four. The title sits on the first; the price, the variant and the quantity and Remove controls share the second, with the controls at the right-hand edge. Where a variant name is long — three options, or a wordy colour — the controls drop to their own line rather than squashing the price. Nothing decides that by screen size: it's the content that doesn't fit, so the same line behaves correctly in the narrow drawer and on a wide cart page. Selling plans, line-item properties and discounts always keep their own full-width row, because they're the parts a shopper most needs to read.

The rewards bar

At the top of the cart and the drawer, up to three spend milestones: free shipping, a free gift, and a discount. Each shows as an icon with its label and threshold, above a segmented progress bar and a message naming the next reward — "You are £12.00 away from Free gift". As the subtotal passes each threshold, that milestone's icon turns to a tick, and the message moves on to the next; past the last one, a celebratory all-unlocked message. Everything re-renders from the server on every cart change, so the ticks and the message can never disagree with the real subtotal.

Each milestone is its own switch in Theme settings → Cart → Rewards bar — run all three, just free shipping (the bar you may know from earlier versions of this theme), or any pair. Milestones display in threshold order regardless of the order you configure them, and each has its own label, icon and threshold. The message wording is yours to change, with [amount] standing in for the remaining amount and [label] for the milestone's label.

The bar is display only — you provide the rewards

Peregrine can't read your shipping rates or discount rules, and it never adds products or changes prices. Each milestone you enable is a promise you are making, so back it with the real mechanism before switching it on:

In short: all three rewards are automatic discounts — Free shipping, Buy X get Y, and Amount off order — created the same way and switched off the same way. The walkthroughs below assume nothing — every click is written out. The example numbers are £50 / £75 / £100; use your own, and make sure each one matches the threshold you type into the theme setting.

Name each discount exactly what you named its milestone. The milestone label in the bar and the discount title at checkout are two halves of the same promise: label the milestone "Free gift" and name the discount "Free gift", and the shopper reads one story — the bar promises it, checkout confirms it ("Free gift −£28.00"). It also makes your own setup one glance to audit: the labels in the theme settings are the titles to look for in your Discounts list.

Everything here is customer-facing, and all of it is yours to word. An automatic discount's title prints on the cart and checkout summary; a shipping rate's name is the delivery option shoppers choose; the milestone labels, icons and messages are theme settings. Any names work — fuller marketing copy like "20% off orders over £100" is fine — what matters is that every enabled milestone has its real mechanism behind it, with matching numbers.

Before you start: an "All products" collection (needed for the gift)

The gift discount will ask which items count towards its minimum spend, and Shopify only lets you pick specific products or collections — there's no "everything" option. So give it everything as a collection:

"But my store already has an All products page" — sort of. The /collections/all page every store serves is a virtual route Shopify generates, not a real collection, so it won't appear in the discount's Browse picker. The collection below is the real, pickable version of the same thing. If you've already created one at some point, use that and skip these steps.

  1. First, one minute on the gift product itself: open it in admin and, under Product organization, set its Product type to Free gift. This is the handle the collection uses to keep it out.
  2. In the admin's left menu, go to Products → Collections, then click Create collection.
  3. Title it All products.
  4. Under Collection type, choose Automated, with Products must match: all conditions.
  5. Add two conditions: Price → is greater than → 0, and Product type → is not equal to → Free gift. Every product you'll ever add matches automatically — except the gift, which is deliberately kept out.
  6. Click Save. If you don't want it appearing in your storefront navigation, simply never link to it — collections only show where you put them.

Why the gift is excluded: the collection defines what counts towards the gift's minimum spend, and the gift counting towards its own qualification is a trap. A shopper £15 short of the threshold could add the gift itself, "qualify" on the strength of the gift's own price, and the moment it goes free the paid subtotal falls back below the threshold — a cart that flickers between qualifying and not. Keeping the gift out means the threshold is always judged on real, paid-for products.

Already have a collection that should define the spend — only full-price items, say? Use that instead, anywhere the steps below say "All products" (and keep the gift out of it the same way).

Step by step: the free-shipping discount

  1. In the admin's left menu, click Discounts, then Create discount, and choose Free shipping.
  2. Under Method, click Automatic discount — the default is a code shoppers would have to type, and the bar promises something that just happens.
  3. Title it with your milestone's label — Free shipping. The title prints on the checkout summary against the zeroed shipping line.
  4. Under Countries, leave All countries, or pick Selected countries if the offer only holds where shipping is cheap for you. This lives entirely inside the discount — your shipping zones aren't touched.
  5. Under Shipping rates sits a checkbox: "Exclude shipping rates over a certain amount". It controls which of your delivery services the discount is allowed to make free, and it works on price:
    • Left unticked — every shipping rate can go free. Whatever service the qualifying shopper picks at checkout — standard, Express, next-day — its price becomes £0. Choose this only if "free shipping" in your store genuinely means any service free.
    • Ticked, with an amount — only rates priced at or below that amount can go free; anything priced above it is excluded and stays at full price. So type an amount just over your standard rate but under your Express rate: if standard is £4.99 and Express is £9.99, enter £6 — the £4.99 standard rate is within the limit and becomes free, the £9.99 Express is over it and stays £9.99, offered as a paid upgrade. This is "free standard shipping", which is what most stores mean by the offer.
    A store with only one shipping rate can leave the box unticked — there's no faster service to accidentally give away.
  6. Under Minimum purchase requirements, select Minimum purchase amount and enter your threshold — £50.
  7. Scroll to the Combinations card — it starts closed, stating the discount won't combine with others. Click the + in its top-right corner to open the options, then tick Product discounts and Order discounts, so free shipping still applies when the gift or the money off is also in play.
  8. Active dates starting today, no end date, Save discount.

Shopify's own reference: Free shipping discounts.

The alternative: a £0 conditional shipping rate. In Settings → Shipping and delivery, add a rate named "Free Shipping" priced £0 to each zone you serve, with Add conditions → Based on order price → Minimum price set to your threshold, keeping your paid rate alongside for shoppers under it. What it buys you: "Free Shipping" appears as a named delivery option shoppers pick, and it sits outside the discount system entirely — no Combinations to manage, and no discount code can displace it. What it costs you: it's per-zone (repeat it everywhere the promise holds), and retiring it means editing rates rather than one Deactivate click. Either route is honest; the discount is simpler to live with, which is why the steps use it. Don't run both at once.

Step by step: the free-gift discount

  1. In the admin's left menu, click Discounts, then Create discount, and choose Buy X get Y.
  2. At the top, under Method, click Automatic discount. This matters: the default is Discount code, which would make shoppers type a code — the rewards bar promises something that just happens.
  3. Title it with your milestone's label — Free gift — remembering the title prints on the shopper's checkout summary.
  4. In Customer buys, select Minimum purchase amount and enter your threshold — £75. In Any items from, choose Specific collections, click Browse, and pick your All products collection. This means: £75 spent across anything in the store — except the gift itself, which the collection deliberately leaves out.
  5. In Customer gets, set Quantity to 1, leave Any items from on Specific products, click Browse, and pick the product you're giving away. A gift card works here too — "spend £75, get a £10 gift card free" is a proven setup, and it's effectively £10 off a future order, which brings shoppers back. If the product has variants (denominations, colours), and only some are the gift, expand it and tick just the variant you're giving — a £10 card, not the whole range.
  6. Under At a discounted value, choose Free.
  7. If you see Set a maximum number of uses per order, tick it and set 1 — otherwise a £150 cart qualifies for two gifts.
  8. Scroll to the Combinations card and click the + in its top-right corner to open the options, then tick Order discounts and Shipping discounts, so the gift can stack with the other two milestones — there's a fuller explanation below.
  9. Leave Active dates starting today with no end date, and click Save discount.

⚠ Shopify never adds the gift to the cart by itself. Its own form says so: the customer must add the gift product — the discount then makes it free. A shopper who crosses £75 and never adds it simply doesn't receive it. Peregrine closes that gap with one more step:

  1. In the theme editor, go to Theme settings → Cart → Rewards bar and set Free gift product to the same product your discount gives away.

With the product picked, the moment a cart crosses the gift threshold the bar itself offers it — image, name and an Add for free button. One tap puts it in the cart at £0, and the row switches to a tick ("Free gift added"). It's deliberately a button, not an automatic add: the theme never puts items in a shopper's cart uninvited.

Gifts with options get a dropdown. If the gift product has more than one variant — a lead in four colours, or a gift card's denominations — the row includes a small selector of the in-stock options, so the shopper picks before tapping. Where the discount covers every variant (choose your free colour), that's the whole feature. Where it covers only one — the £10 card out of five denominations — the other choices exist in the dropdown but fail the price check below and are removed, not charged; word the milestone so shoppers pick the right one ("Free £10 gift card"), and the label of a wrong pick sorts itself out honestly.

The gift doesn't take up a line in the cart. Once it's in and free, the bar's row is its representation — "Free gift added", with its own Remove — and the item itself is folded out of the list, so the cart stays about what the shopper chose to buy. It's still in the cart and still on the order; it just isn't repeated. Three things keep that honest:

And it checks your homework. The theme can't read your discounts, so after the tap it verifies the line Shopify sent back is actually free. If it isn't — discount missing, wrong minimum, Combinations conflict — the theme removes the item again and tells the shopper the gift couldn't be applied, rather than leaving a full-price "gift" in the cart. If you ever see that message during testing, the discount setup above is where to look. (With JavaScript off the button is a plain add-to-cart form and this check can't run — one more reason to get the numbers matching.)

If the cart later drops below the threshold, Shopify reprices the gift — and frees it again the moment the shopper re-qualifies. So the theme doesn't remove it (that would break the self-healing); instead the cart states it plainly: the order no longer qualifies, add more to unlock it again or remove it. The message clears by itself as soon as either happens.

Gift lines added by the bar's button sit at the bottom of the cart whatever order things were added in, with no quantity stepper (a free gift is quantity one by nature) and Remove beside the price — a bonus reads as a bonus, not another purchase. A gift product the shopper buys normally from its product page is an ordinary line and behaves like one.

Leave Free gift product empty and the milestone is display only — the icon, tick and messages still work; shoppers just find the gift themselves. In that case, word the milestone so they know to ("Free gift — add it to your cart"), and consider curating the gift into the cart's recommendations.

Shopify's own reference: Buy X get Y discounts.

Step by step: the order discount

  1. Discounts → Create discount again, and this time choose Amount off order.
  2. Under Method, click Automatic discount — same reason as before.
  3. Title it with the milestone's label — 20% off.
  4. Under Discount value, choose Percentage and enter 20.
  5. Under Minimum purchase requirements, select Minimum purchase amount and enter your threshold — £100.
  6. Scroll to the Combinations card and click the + in its top-right corner to open the options, then tick Product discounts and Shipping discounts, so this can stack with the gift and with free shipping.
  7. Active dates starting today, no end date, Save discount.

Shopify's own reference: Discounts.

Why the Combinations ticks matter

Shopify applies one automatic discount unless they're set to combine. Every discount belongs to a class — free shipping is a shipping discount, the gift a product discount, the 20% an order discount — and each discount's Combinations panel declares which classes it stacks with. Two discounts only stack when each ticks the other's class, so three milestones need the full three-way handshake, which is what the Combinations steps above set up: every discount accepting the other two classes. Miss a tick and a cart past every threshold gets a subset of the rewards, whichever Shopify picks — while the bar's ticks promise all three. Shopify's own reference: Combining discounts.

Turning a milestone off? Turn its reward off too

The switches in the theme only control the display. Untick the gift milestone and the Buy X get Y discount carries on applying at checkout — every qualifying order keeps getting the gift, you've just stopped telling anyone. Same for the order discount, and for the shipping rate. That's the reverse of the empty-promise problem: not dishonest, but a quiet ongoing cost you probably didn't mean to keep paying.

So retiring a milestone is a two-step, mirroring its setup: switch it off in the theme, then Discounts → open the discount → Deactivate — the same one click for all three (deactivating keeps it ready to reactivate next time; deleting is forever). If you built free shipping as a £0 rate instead of a discount, its off-switch lives where it was made: edit or delete the rate in Settings → Shipping and delivery. Running a reward without the bar deliberately — a quiet perk you don't advertise — is a perfectly valid choice; just make it a choice.

Then test it — five minutes, before your shoppers do

  1. Open your storefront and add something small. The bar should show the amount remaining to your first milestone.
  2. Keep adding until you cross each threshold — each icon should turn to a tick as you pass it, and the message should move on to the next milestone.
  3. Past the gift threshold, the bar should offer the gift with its Add for free button (if you've set Free gift product) — tap it and the row should switch to "Free gift added" with a Remove beside it, and no separate line in the cart. Now take the cart back under the threshold: the gift should disappear from the cart on its own — never showing as a priced line — and the bar should go back to counting down towards it. Cross back over and it should be offered again. No product picked? Add the gift from its product page instead and watch the line go free.
  4. Go to checkout: past £50 the standard shipping rate should show as Free (struck through, with your discount's name against it); past £100 the 20% should be on the summary alongside the gift. Seeing some rewards but not others is the Combinations handshake missing a tick.
  5. If a milestone ticks but checkout doesn't deliver it, compare the number in the theme setting against the number on the rate or discount — they must match exactly.

Your other discounts follow the same rules. The theme enforces none of this — Shopify's discount engine decides at checkout, and the bar is signage over it. A sale or any other discount stacks with the milestone rewards only where Combinations allow it on both sides. The sharp edge is discount codes: a code that isn't combinable with your automatic discounts will displace them at checkout, so a code-using shopper can lose the milestone rewards the bar promised. If you run codes alongside the rewards bar, either make them combinable or accept that trade knowingly. (One nuance: free shipping built as a £0 rate — the alternative route above — sits outside the discount system entirely, so it always applies when the order qualifies and no code can displace it. Built as a discount, it plays by the same combination rules as the other two.)

Get a threshold wrong and the bar will promise something checkout doesn't deliver — the settings repeat this warning next to the gift and discount switches for exactly that reason.

Shoppers in other currencies

You set your thresholds once, in your store's main currency, and the bar handles every other currency itself. There is no second list to maintain and nothing to update when exchange rates move.

When a shopper is browsing in another market's currency, the theme converts your thresholds using Shopify's own live exchange rate — the same rate, applied the same way, that Shopify uses to convert your product prices. A £50 milestone reads as $70 to a US shopper on a store where £52 products show as $72. The rate comes fresh from Shopify on every page, so if it shifts overnight the bar shifts with it the next morning without you touching the theme.

Your discounts already work this way, which is why the two stay in step. You enter a minimum purchase amount on a Shopify discount in your main currency, and Shopify converts that minimum for each market at checkout. One number in the theme setting, one number on the discount, every market covered.

Two things worth knowing:

Recommendations

Off by default, on two separate switches. A cart's job is to get the shopper to checkout, so Peregrine ships with the cart showing only what's in it. When you do want cross-sells, Theme settings → Cart → Recommendations turns them on per surface:

Both surfaces show them as a carousel, not a grid. Your setting says how many products the carousel holds; shoppers see as many as fit and move through the rest with the arrows beside the heading — so recommendations never push the cart items and the checkout button down the page. The arrows appear only when there's more to see: set it to three on a wide screen and there's nothing to press, so nothing is shown. The row also scrolls by swipe and trackpad, which is how it behaves on a phone.

Whichever you enable, the source is the same. If you've curated complementary products in Shopify's free Search & Discovery app (the same lists the product page's "Goes well with" block uses), those show first — your choices, filtered of anything already in the cart. Where you haven't curated, Shopify's own recommendations engine fills in. When neither has anything to say, nothing renders — no empty heading, no placeholder row. With both switches off no recommendation markup is produced at all, and nothing is fetched.

Adding straight from a recommendation

Theme settings → Cart → Add to cart from the recommendation (on by default) puts a variant dropdown and an Add to cart button on each suggestion, sharing one row under the price. A shopper can add a cross-sell without leaving the cart — which is the whole point of showing it there.

What appears depends on the product, and the theme never guesses on the shopper's behalf:

Where a product's variants are priced differently, choosing one updates the price shown on the tile. Adding never navigates away: the cart updates in place and the button confirms. It also works with JavaScript switched off — each tile is a real form, so it posts and lands on the cart with the variant the shopper picked.

Turn it off and recommendations go back to being pictures that link to the product — useful if your products need explaining before anyone should be adding them.

When the same product appears on two lines

This is Shopify, not the theme, and it usually means a discount is working. Shopify keeps cart lines separate when their units have earned different things. The common case is a Buy X get Y offer, like the free gift milestone: if two units of a product earned the gift and a third didn't, Shopify holds the entitled two and the unentitled one as separate lines — same product, same size, same everything the shopper can see.

Peregrine combines them for you. Theme settings → Cart → Combine duplicate lines (on by default) shows one row per product with the quantities added together, so the cart doesn't look like it duplicated something.

Two things to know before you rely on it:

Editing a combined row behaves the way you'd expect — changing the quantity or removing it acts on the whole row, in one instruction, with or without JavaScript. Shopify may split the product again after a later change; the cart simply combines it again, so the row stays put.

Totals and checkout

The totals column shows the subtotal, any cart-level discounts by name, and whether taxes are included — using Shopify's own figures on every change. An optional order note box (on by default, switchable under Theme settings → Cart → Show the order note box) saves as the shopper types and arrives with the order in your admin. The same switch governs the slide-out cart, where the note appears as an Order note row you can open — so it takes one line until a shopper wants it, rather than crowding a panel that is already showing your rewards bar, the items and any recommendations. Discount codes are entered at checkout, where Shopify validates them properly.

Express checkout buttons

Under the Checkout button, both the cart page and the slide-out cart show whichever express methods you have switched on — Shop Pay, PayPal, Google Pay, Apple Pay and the rest. There is nothing to enable in the theme: they come from Settings → Payments in Shopify admin, and if you have none turned on, nothing is rendered and no space is taken.

They sit below your own Checkout button rather than above it, so your store's own checkout stays the primary action. Peregrine sizes them from your own button settings, so on the cart page they match the corner radius and height of the Checkout button above them — change your button padding in Theme settings → Buttons and they follow.

The two surfaces lay them out differently, on purpose:

On the cart page the express buttons appear in the page itself, not in the slide-out cart — showing both at once would put two copies of Shopify's checkout component on one page, which breaks it.

These buttons are rendered by Shopify, not by the theme, which is deliberate — they carry payment credentials, so their appearance and behaviour are controlled by Shopify and can only be styled within the limits Shopify allows. That is also why they can look slightly different from store to store depending on which methods a shopper's device supports, and why a wallet only appears for shoppers whose device or browser offers it.

How updates work

Every change — a quantity step, a removal, an add from anywhere — is sent to Shopify and the cart re-renders from the response. The theme does no arithmetic of its own on money, with one deliberate exception: converting your rewards-bar thresholds for a shopper in another currency, which Shopify gives no way to do on the server. Everything else — subtotals, discounts, line prices — is Shopify's own figure, so nothing can drift from what checkout will actually charge. If Shopify refuses a change (not enough stock, say), its own message appears above the lines and the cart stays as it was.

The drawer is fully keyboard-accessible: focus moves into it when it opens, stays trapped while it's open, Esc closes it, and focus returns to where it was.