shadcn.io is not affiliated with official shadcn/ui
Item Variants Checkout Block for Vue
A trail jacket shop's cart with an Edit options popover shown open: six sizes with Sold out and a surcharge named, three colours drawn in words, a price line that follows, and Update that rewrites the row.
Installation
Overview
Let people fix a size or a colour from the cart itself, with this variant editor for Vue with Ark UI. It opens from the cart of Gannet Outfitters, a shop for trail jackets and shells: the page's header holds an outline Edit options Button, and the cart, three drawn rows and a total bar, sits in a hairline frame with a plus mark on each corner. The editor is a small non-modal Popover for the Ridgeline shell with a size from XS to XXL (XS says Sold out and can't be picked, XXL says it costs $6.00 more), three colours named in words and drawn without hue (Slate solid, Sand pale, Pine hatched), and a price line that follows the choice, such as "+$6.00 for XXL, now $146.00". Cancel throws the choice away; Update, the only Shine Button, rewrites the drawn row behind the popover, says so in a polite line and returns focus to the button. Prices are whole cents. For preview the popover is drawn open in place when the page loads; the header button opens the real Popover, with the same choices and the same state. For apparel, shoes, furniture and any cart line that has options.
FAQ
Why is the popover already open, and what do I keep?
So you can see it without a click. On load the editor is a copy drawn in place at the end of the cart: a native non-modal dialog element with no scrim, so nothing is trapped or focused, and the page around the preview keeps working. The Edit options button opens the real editor as a non-modal Popover that hangs from the button (Escape closes it and focus goes back to the button), and the copy stays closed until a reload. Both show the same Fields component inside their own form and share the block's state. In your app keep the Popover and drop the copy: the "in-place" state, the dialog and the Escape effect.
How do the sizes and colours work from the keyboard?
Each group is a native radio group behind styled labels, so Tab enters it, the arrow keys move between the choices and the choice you stop on is the one picked, and a sold-out size is skipped because its radio is disabled. The words say what the colour can't: "Sold out" sits in the cell, struck through, and the three colours carry their names. Nothing is told by hue alone.
How is the price worked out?
The jacket costs 14000 cents and each size adds a typed number of cents (XXL adds 600), so the line under the choices is the base plus the extra, written by usd, the only place cents become text. Pick a size with no surcharge and the line says it is the base price. Add a surcharge to another size in SIZES and the line, the drawn row and the status message all follow.
What do Update and Cancel do?
Update commits the choice to the drawn row, so the stage behind the popover shows the new size, colour and price, closes the popover and puts focus back on Edit options, and a polite message says "Ridgeline shell: XXL, Pine, $146.00. Updated in this demo." Cancel, Escape or a click outside discard the draft: the next time the popover opens it starts from what the row says now.
Is it accessible from the keyboard?
Yes. The popover is named Edit options, the choices are labelled groups (Size, Colour), and Escape closes it and returns focus to the button. The trigger is the button wrapped in PopoverTrigger with asChild, and the popover is controlled with open and onOpenChange and is not modal. Update is the form's submit button, so Enter inside the choices submits. The copy shown on load moves no focus; Escape inside it closes it and puts focus on the button.
What stays local in the demo, and how do I wire it up?
Everything. The row is drawn, the choice lives in the block's state and Update only changes that state; nothing is ordered. In your app read the options and their stock from the product, send the new variant to your cart API from the update handler (and show a failure in the same status line), and disable a size from live stock rather than the typed soldOut flag.