Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Comparison Upsell Checkout Block for Svelte

A kettle in your cart set beside the one a size up: two drawn cells, a native table of five attributes with ticks and dashes in words, a price difference worked out in cents, and Upgrade for $22.00 more with a Back to the 1 L that undoes it.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Show people what the next size up gets them before they pay, with this comparison upsell for Svelte with Ark UI. A compact header from Brindle and Birch, a kitchen-appliance shop, sits over a hairline frame with a plus mark on each corner. Two cells side by side hold the kettle in your cart and the one above it: a drawn kettle, a Badge saying which is in your cart, the name, the price and a line that says how much more or less it costs than the cart. Under them one native table compares five attributes (capacity, boil time, temperature presets, keep-warm and warranty), each answered with a tick or a dash and the answer in words, so nothing depends on an icon. The foot holds the one Shine Button, Upgrade for $22.00 more, which swaps the cart line, moves the In your cart tag to the 1.7 L cell and counts the total up (Counting Number); afterwards it reads Continue to shipping, and an outline Button, Back to the 1 L, swaps back. A polite status line says what each press did. For product pages and carts where one step up is worth showing, with two physical products and not plan tiers.

FAQ

How do I compare my own two products?

Edit SMALL and LARGE (an id, a name and a price in whole cents) and the SPECS list. Each spec has a label, an answer for each product and a flag for each saying whether it has the feature, which picks the tick or the dash. The difference, the cell tags and the total are all worked out from the two prices, so no figure is typed twice. Swap Drawing for your product pictures and keep the name in text beside them.

How does the swap and its undo work?

One state value says which kettle is in the cart. Upgrade sets it to the larger one; Back to the 1 L sets it back. Both buttons stay on the page: Back to the 1 L is always rendered and marked unavailable until you have upgraded, and pressing it before then says so in the status line instead of doing nothing silently. The Shine Button is the same element throughout, so keyboard focus stays on it when its label changes.

Why does every tick and dash have words beside it?

Colour and shape alone fail for people who cannot see them, and a dash does not say whether a feature is missing or just not listed. Each cell shows the answer ("None", "No", "30 minutes") with a small icon marked as decorative, and the table has a hidden caption, column heads and row heads, so a screen reader announces each answer with its attribute and product.

Why are prices in cents?

Floating-point dollars drift (0.1 + 0.2), so every price is an integer number of cents and usd is the only place that turns cents into text. The difference is the larger price minus the smaller one, and the cart total counts to its new value when you swap.

How does it look on a phone?

The two cells stack, the cart item first and the upgrade under it, and the table keeps its three columns with the answers wrapping inside them. The foot is pinned to the bottom of the screen while you scroll, with the status line above a two-column row of the Shine Button and Back to the 1 L, and settles at the panel's end from the medium breakpoint.

What stays local in the demo, and how do I wire it up?

Everything. The cart line lives in the block's state, and Continue to shipping only says that shipping comes next; nothing is ordered. In your app, make the upgrade a call to your cart API that replaces the line and returns the new total, show its error in the same status line if it fails, and make Continue to shipping a link to your next step: wrap an a element in the Shine Button with asChild.